51IO口模拟串口通讯C源程.docx
- 文档编号:3515928
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:26
- 大小:25.13KB
51IO口模拟串口通讯C源程.docx
《51IO口模拟串口通讯C源程.docx》由会员分享,可在线阅读,更多相关《51IO口模拟串口通讯C源程.docx(26页珍藏版)》请在冰豆网上搜索。
51IO口模拟串口通讯C源程
51IO口模拟串口通讯C源程
--------------------------------------------------------------------------------
#include
sbitBT_SND=P1^0;
sbitBT_REC=P1^1;
/**********************************************
IO口模拟232通讯程序使用两种方式的C程序占用定时器0
**********************************************/
#defineTIMER0_ENABLETL0=TH0;TR0=1;
#defineTIMER0_DISABLETR0=0;
volatileunsignedcharF_TM;
voidIntTimer0()interrupt1
{
F_TM=1;
}
//发送一个字符
voidPSendChar(unsignedcharinch)
{
unsignedcharii;
ii=0;
F_TM=0;
BT_SND=0;//startbit
TIMER0_ENABLE;//启动
while(!
F_TM);
while(ii<8)
{
if(inch&1)
{
BT_SND=1;
}
else
{
BT_SND=0;
}
F_TM=0;
while(!
F_TM);
ii++;
inch>>=1;
}
BT_SND=1;
F_TM=0;
while(!
F_TM);
TIMER0_DISABLE;//停止timer
}
//接收一个字符
unsignedcharPGetChar()
{
unsignedcharrch,ii;
TIMER0_ENABLE;
F_TM=0;
ii=0;
rch=0;
while(!
F_TM);//等过起始位
while(ii<8)
{
rch>>=1;
if(BT_REC)
{
rch|=0x80;
}
ii++;
F_TM=0;
while(!
F_TM);
}
F_TM=0;
while(!
F_TM)
{
if(BT_REC)
{
break;
}
}
TIMER0_DISABLE;//停止timer
returnrch;
}
//检查是不是有起始位
bitStartBitOn()
{
return(BT_REC==0);
}
voidmain()
{
unsignedchargch;
TMOD=0x22;/*定时器1为工作模式2(8位自动重装),0为模式2(8位自动重装)*/
PCON=00;
TR0=0;//在发送或接收才开始使用
TF0=0;
TH0=(256-96);//9600bps就是1000000/9600=104.167微秒执行的timer是104.167*11.0592/12=96
TL0=TH0;
ET0=1;
EA=1;
PSendChar(0x55);
PSendChar(0xaa);
PSendChar(0x00);
PSendChar(0xff);
while
(1)
{
if(StartBitOn())
{
gch=PGetChar();
PSendChar(gch);
}
}
}
51单片机模拟串口的三种方法
上海聚龙电力技术有限公司 舒兵
随着单片机的使用日益频繁,用其作前置机进行采集和通信也常见于各种应用,一般是利用前置
机采集各种终端数据后进行处理、存储,再主动或被动上报给管理站。
这种情况下下,采集会需
要一个串口,上报又需要另一个串口,这就要求单片机具有双串口的功能,但我们知道一般的51
系列只提供一个串口,那么另一个串口只能靠程序模拟。
本文所说的模拟串口, 就是利用51的两个输入输出引脚如P1.0和P1.1,置1或0分别代表高低电
平,也就是串口通信中所说的位,如起始位用低电平,则将其置0,停止位为高电平,则将其置
1,各种数据位和校验位则根据情况置1或置0。
至于串口通信的波特率,说到底只是每位电平持续
的时间,波特率越高,持续的时间越短。
如波特率为9600BPS,即每一位传送时间为
1000ms/9600=0.104ms,即位与位之间的延时为为0.104毫秒。
单片机的延时是通过执行若干条
指令来达到目的的,因为每条指令为1-3个指令周期,可即是通过若干个指令周期来进行延时的,
单片机常用11.0592M的的晶振,现在我要告诉你这个奇怪数字的来历。
用此频率则每个指令周期
的时间为(12/11.0592)us,那么波特率为9600BPS每位要间融多少个指令周期呢?
指令周期s=(1000000/9600)/(12/11.0592)=96,刚好为一整数,如果为4800BPS则为
96x2=192,如为19200BPS则为48,别的波特率就不算了,都刚好为整数个指令周期,妙吧。
至于
别的晶振频率大家自已去算吧。
现在就以11.0592M的晶振为例,谈谈三种模拟串口的方法。
方法一:
延时法
通过上述计算大家知道,串口的每位需延时0.104秒,中间可执行96个指令周期。
#define uchar unsigned char
sbit P1_0 = 0x90;
sbit P1_1 = 0x91;
sbit P1_2 = 0x92;
#define RXD P1_0
#define TXD P1_1
#define WRDYN 44 //写延时
#define RDDYN 43 //读延时
//往串口写一个字节
void WByte(uchar input)
{
uchar i=8;
TXD=(bit)0; //发送启始
位
Delay2cp(39);
//发送8位数据位
while(i--)
{
TXD=(bit)(input&0x01); //先传低位
Delay2cp(36);
input=input>>1;
}
//发送校验位(无)
TXD=(bit)1; //发送结束
位
Delay2cp(46);
}
//从串口读一个字节
uchar RByte(void)
{
uchar Output=0;
uchar i=8;
uchar temp=RDDYN;
//发送8位数据位
Delay2cp(RDDYN*1.5); //此处注意,等过起始位
while(i--)
{
Output >>=1;
if(RXD) Output |=0x80; //先收低位
Delay2cp(35); //(96-26)/2,循环共
占用26个指令周期
}
while(--temp) //在指定的
时间内搜寻结束位。
{
Delay2cp
(1);
if(RXD)break; //收到结束位便退出
}
return Output;
}
//延时程序*
void Delay2cp(unsigned char i)
{
while(--i); //刚好两个
指令周期。
}
此种方法在接收上存在一定的难度,主要是采样定位存在需较准确,另外还必须知道
每条语句的指令周期数。
此法可能模拟若干个串口,实际中采用它的人也很多,但如果你用Keil
C,本人不建议使用此种方法,上述程序在P89C52、AT89C52、W78E52三种单片机上实验通过。
方法二:
计数法
51的计数器在每指令周期加1,直到溢出,同时硬件置溢出标志位。
这样我们就可以
通过预置初值的方法让机器每96个指令周期产生一次溢出,程序不断的查询溢出标志来决定是否
发送或接收下一位。
//计数器初始化
void S2INI(void)
{
TMOD |=0x02; //计数器0,方式2
TH0=0xA0; //预值为256-96=140,十六进制A0
TL0=TH0;
TR0=1; //开始计数
TF0=0;
}
void WByte(uchar input)
{
//发送启始位
uchar i=8;
TR0=1;
TXD=(bit)0;
WaitTF0();
//发送8位数据位
while(i--)
{
TXD=(bit)(input&0x01); //先传低位
WaitTF0();
input=input>>1;
}
//发送校验位(无)
//发送结束位
TXD=(bit)1;
WaitTF0();
TR0=0;
}
//查询计数器溢出标志位
void WaitTF0( void )
{
while(!
TF0);
TF0=0;
}
接收的程序,可以参考下一种方法,不再写出。
这种办法个人感觉不错,接收和发送
都很准确,另外不需要计算每条语句的指令周期数。
方法三:
中断法
中断的方法和计数器的方法差不多,只是当计算器溢出时便产生一次中断,用户可以
在中断程序中置标志,程序不断的查询该标志来决定是否发送或接收下一位,当然程序中需对中
断进行初始化,同时编写中断程序。
本程序使用Timer0中断。
#define TM0_FLAG P1_2 //设传输标志位
//计数器及中断初始化
void S2INI(void)
{
TMOD |=0x02; //计数器0,方式2
TH0=0xA0; //预值为256-96=140,十六进制A0
TL0=TH0;
TR0=0; //在发送或
接收才开始使用
TF0=0;
ET0=1; //允许定时
器0中断
EA=1; //中断允许
总开关
}
//接收一个字符
uchar RByte()
{
uchar Output=0;
uchar i=8;
TR0=1; //启动Timer0
TL0=TH0;
WaitTF0(); //等过起始
位
//发送8位数据位
while(i--)
{
Output >>=1;
if(RXD) Output |=0x80; //先收低位
WaitTF0(); //位间延时
}
while(!
TM0_FLAG) if(RXD) break;
TR0=0; //停止
Timer0
return Output;
}
//中断1处理程序
void IntTimer0() interrupt 1
{
TM0_FLAG=1; //设置标志位。
}
//查询传输标志位
void WaitTF0( void )
{
while(!
TM0_FLAG);
TM0_FLAG=0; //清标志位
}
中断法也是我推荐的方法,和计数法大同小异。
发送程序参考计数法,相信是件很容
易的事。
另外还需注明的是本文所说的串口就是通常的三线制异步通信串口(UART),只用RXD、TXD、
GND。
通用的I/O模拟串口程序
//UART.C
//
//GenericsoftwareuartwritteninC,requiringatimersetto3times
//thebaudrate,andtwosoftwareread/writepinsforthereceiveand
//transmitfunctions.
//
//*Receivedcharactersarebuffered
//*putchar(),getchar(),kbhit()andflush_input_buffer()areavailable
//*Thereisafacilityforbackgroundprocessingwhilewaitingforinput
//
//ColinGittins,SoftwareEngineer,HalliburtonEnergyServices
//
//ThebaudratecanbeconfiguredbychangingtheBAUD_RATEmacroas
//follows:
//
//#defineBAUD_RATE19200.0
//
//Thefunctioninit_uart()mustbecalledbeforeanycommscantakeplace
//
//Interfaceroutinesrequired:
//1.get_rx_pin_status()
//Returns0or1dependentonwhetherthereceivepinishighorlow.
//2.set_tx_pin_high()
//Setsthetransmitpintothehighstate.
//3.set_tx_pin_low()
//Setsthetransmitpintothelowstate.
//4.idle()
//Backgroundfunctionstoexecutewhilewaitingforinput.
//5.timer_set(BAUD_RATE)
//Setsthetimerto3timesthebaudrate.
//6.set_timer_interrupt(timer_isr)
//Enablesthetimerinterrupt.
//
//Functionsprovided:
//1.voidflush_input_buffer(void)
//Clearsthecontentsoftheinputbuffer.
//2.charkbhit(void)
//Testswhetheraninputcharacterhasbeenreceived.
//3.chargetchar(void)
//Readsacharacterfromtheinputbuffer,waitingifnecessary.
//4.voidturn_rx_on(void)
//Turnsonthereceivefunction.
//5.voidturn_rx_off(void)
//Turnsoffthereceivefunction.
//6.voidputchar(char)
//Writesacharactertotheserialport.
#include
#defineBAUD_RATE19200.0
#defineIN_BUF_SIZE256
#defineTRUE1
#defineFALSE0
staticunsignedcharinbuf[IN_BUF_SIZE];
staticunsignedcharqin=0;
staticunsignedcharqout=0;
staticcharflag_rx_waiting_for_stop_bit;
staticcharflag_rx_off;
staticcharrx_mask;
staticcharflag_rx_ready;
staticcharflag_tx_ready;
staticchartimer_rx_ctr;
staticchartimer_tx_ctr;
staticcharbits_left_in_rx;
staticcharbits_left_in_tx;
staticcharrx_num_of_bits;
staticchartx_num_of_bits;
staticcharinternal_rx_buffer;
staticcharinternal_tx_buffer;
staticcharuser_tx_buffer;
voidtimer_isr(void)
{
charmask,start_bit,flag_in;
//TransmitterSection
if(flag_tx_ready)
{
if(--timer_tx_ctr<=0)
{
mask=internal_tx_buffer&1;
internal_tx_buffer>>=1;
if(mask)
{
set_tx_pin_high();
}
else
{
set_tx_pin_low();
}
timer_tx_ctr=3;
if(--bits_left_in_tx<=0)
{
flag_tx_ready=FALSE;
}
}
}
//ReceiverSection
if(flag_rx_off==FALSE)
{
if(flag_rx_waiting_for_stop_bit)
{
if(--timer_rx_ctr<=0)
{
flag_rx_waiting_for_stop_bit=FALSE;
flag_rx_ready=FALSE;
internal_rx_buffer&=0xFF;
if(internal_rx_buffer!
=0xC2)
{
inbuf[qin]=
internal_rx_buffer;
if(++qin>=IN_BUF_SIZE)
{
qin=0;
}
}
}
}
else//rx_test_busy
{
if(flag_rx_ready==FALSE)
{
start_bit=get_rx_pin_status();
//TestforStartBit
if(start_bit==0)
{
flag_rx_ready=TRUE;
internal_rx_buffer=0;
timer_rx_ctr=4;
bits_left_in_rx=
rx_num_of_bits;
rx_mask=1;
}
}
else//rx_busy
{
if(--timer_rx_ctr<=0)
{
//rcv
timer_rx_ctr=3;
flag_in=
get_rx_pin_status();
if(flag_in)
{
internal_rx_buffer|=rx_mask;
}
rx_mask<<=1;
if(--
bits_left_in_rx<=0)
{
flag_rx_waiting_for_stop_bit=TRUE;
}
}
}
}
}
}
voidinit_uart(void)
{
flag_tx_ready=FALSE;
flag_rx_ready=FALSE;
flag_rx_waiting_for_stop_bit=FALSE;
flag_rx_off=FALSE;
rx_num_of_bits=10;
tx_num_of_bits=10;
set_tx_pin_low();
timer_set(BAUD_RATE);
set_timer_interrupt(timer_isr);//Enabletimerinterrupt
}
char_getchar(void)
{
charch;
do
{
while(qout==qin)
{
idle();
}
ch=inbuf[qout]&0xFF;
if(++qout>=IN_BUF_SIZE)
{
qout=0;
}
}
while(ch==0x0A||ch==0xC2);
return(ch);
}
void_putchar(charch)
{
while(flag_tx_ready);
user_tx_buffer=ch;
//invoke_UART_transmit
timer_tx_ctr=3;
bits_left_in_tx=tx_num_of_bits;
internal_tx_buffer=(user_tx_buffer<<1)|0x200;
flag_tx_ready=TRUE;
}
voidflush_input_buffer(void)
{
qin=0;
qout=0;
}
charkbhit(void)
{
return(qin!
=qout);
}
voidturn_rx_on(void)
{
flag_rx_off=FALSE;
}
voidturn_rx_off(void)
{
flag_rx_off=TRUE;
}
MSC51汇编代码编写的模拟串口程序
T2作为波特率控制
UART_RXD是硬中断0或1口,如果能进入中断,说明该线有一个起始位
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 51 IO 模拟 串口 通讯 源程
![提示](https://static.bdocx.com/images/bang_tan.gif)