首页 > 编程知识 正文

51单片机有一个全双工,uart串口通信原理

时间:2023-05-04 14:57:23 阅读:136281 作者:3842

优化《51单片机——USART半双工模式通讯-波特率可选1.2版本》的代码。

2、主要修改串口中断中的代码和主函数中的发送代码,接收缓存50字节(它可以自己调节串口缓存的大小)。

3、该代码在半双工模式下工作。

4、使用系统输出函数后,使用自定义函数发送需要2毫秒的延迟,否则会出错。 你要牢牢记住。

测试结果:定时器1、定时器2波特率均验证OK。 4800bps~115200bps是可以的。

main.c

# include ' UART.h ' # include stdio.h # include ' delay.h ' # define UART _ t1///1的话用计时器1显示波特率,0的话用计时器2显示波特率//这是串口为全双工模式。本实验50字节缓存//注释:上位机必须在数据后加'n '或换行符//注释。 delay在调试时至少延迟2毫秒(如果使用系统输出函数) (换行到voidmain )//puts ) {unsigned char num_x=0; if(UART_T1 ) UART_T1_init_config(1; //要使用将串行端口波特率初始化为最大57600ES=0的printf,首先关闭串行并中断TI=1; //在使用系统函数之前必须将TI设置为1puts () 1、计时器1发生波特率,测试结果为pass; printf(2、计时器1发生波特率,测试结果为pass(n ); ES=1; //启动串行端口并中断delay_ms(2); //不知道为什么需要延迟,否则接收到数据会出错的UART_send_string(rx ); //发送默认数据}else{UART_T2_init_config(5; //要使用将串行端口波特率初始化为最大115200ES=0的printf,首先关闭串行并中断TI=1; //在使用系统函数之前将TI设置为1puts(1,使计时器2产生波特率,测试结果为pass ); printf(2,计时器2产生波特率,测试结果为pass(n ); ES=1; //启动串行端口并中断delay_ms(2); //不知道为什么需要延迟,否则接收到数据会出错的UART_send_string(rx ); //发送默认数据}for (; RX[num_x]!='n '; num_x(/清空缓冲区并写入换行符(n ) ) rx[num_x]='n '; if(num_x%2!=0)/1汉字占用2个字节,如果不用汉字打印,则该行代码Uart_send_string(rx ); //发送删除后的数据}num_x=0; while(1) if ) flag_rx ) /收到数据后重新发送(Uart_send_1byte_data ) rx[num_x] ); if(rx[num_x]=='n ' ) {num_x=0; flag_rx=0; }else{num_x; }}}} delay.c和delay.h太简单了,所以不贴代码

uart.h

# ifndef _ _ UART _ h _ # define _ _ UART _ h _ # includereg 52.h//mode _ n _ bps输入示例,计时器1具有115200////bps //最多50字节//保存串行端口初始化挂载,使用计时器1生成波特率。 默认值为9600 bpsvoiduart _ t1 _ init _ config (unsignedcharmode _ n _ bps ); //串行端口初始化负载,计时器2生成波特率//串行端口的工作方式1,8位uart下波特率可变,串行端口发送数据//允许接收默认波特率9600 bpsvoiduart _ T2 _ init _ config (unsignedcharmode _ n _ bps )//串行传输数据void UART _ send _ send //串行发送字符串void UART _ send _ string (unsigned char * c ); #endif //! __UART_H__ uart.c

#include 'uart.h'sfr IPH_=0xB7; //中断优先级高位寄存器sfr SADEN_=0xB9; //从站地址掩码寄存器sfr SADDR_=0xA9; //从地址控制寄存器static bit flag_tx=0; //发送空闲显示位bit flag_rx=0; //接收忙标志unsigned char RX[53]='最多只能发送25个字符的汉字,最后必须有回车。 哈rn '; //最多初始化50字节//超过串口的挂载,使用定时器1生成波特率//串口的工作方式1、8位uart,可变波特率,串口为数据//定时器1的工作方式2、 允许8位自动重载模式void uart _ t1 _ init _ config (unsignedcharmonfig ) )//串行端口工作方式为1.8位UART,波特率可变,串行端口数据//最高SMOD=1表示串行端口工作模式1、2

、3下加倍波特率(默认PCON=0x10,波特率不加倍)SADEN_ = 0x00;//不使用SADDR_ = 0x00;//不使用TI=0;//清除RI=0;//清除EA = 1;//打开总中断ES = 1;//打开串口中断//串口1中断优先级0IPH_ = 0x00;IP = 0x00;TMOD |= 0x20;//开启定时器T1,并使用工作方式2(8位自动重装)switch(Mode_n_bps){case 1:TL1 = 250;//计数初值设置波特率4800bpsTH1 = 250;//装载固定初值,当TL1加满后会自动把TH1的值装载进去break;//bps4800case 2:TL1 = 253;//计数初值设置波特率9600bpsTH1 = 253;//装载固定初值,当TL1加满后会自动把TH1的值装载进去break;//bps9600case 3:PCON |= 0x80;//SM0D=1,波特率加倍TL1 = 253;//计数初值设置波特率19200bpsTH1 = 253;//装载固定初值,当TL1加满后会自动把TH1的值装载进去break;//bps19200case 4:PCON |= 0x80;//SM0D=1,波特率加倍TL1 = 255;//计数初值设置波特率57600bpsTH1 = 255;//装载固定初值,当TL1加满后会自动把TH1的值装载进去break;//bps57600default://默认bps9600TL1 = 253;//计数初值设置波特率9600bpsTH1 = 253;//装载固定初值,当TL1加满后会自动把TH1的值装载进去break;//bps9600}ET1 = 0;//禁止定时器1发出中断TR1 = 1;//启动定时器1}//串口初始化装载,使用定时器2产生波特率//串口工作方式1,8位uart且波特率可变,且允许串口接收数据void UART_T2_init_config(unsigned char Mode_n_bps)//默认波特率9600bps{SCON = 0x50;//串口工作方式1,8位uart且波特率可变,且允许串口接收数据T2CON |= 0x30;//定时器2用作串口波特率发生器且16位自动重装模式SADEN_ = 0x00;//不使用,默认值SADDR_ = 0x00;//不使用。默认值TI=0;//清除,建议清除一下RI=0;//清除EA = 1;//打开总中断ES = 1;//打开串口中断//串口1中断优先级0IPH_ = 0x00;//默认值IP = 0x00;//默认值//T2MOD = 0x02;//T2OE :T2 输出允许位,当 T2OE=1 的时候,允许时钟输出到 P1.0。(仅对80C54 / 80C58 有效)//DCEN:向下计数允许位。 DCEN = 1 是允许 T2 向下计数,否则向上计数。switch (Mode_n_bps){case 1:TL2 = 0xb8;//计数初值设置波特率4800bpsTH2 = 0xff;//装载固定初值RCAP2L = 0xb8;RCAP2H = 0xff;break;//bps4800case 2:TL2 = 0xdc;//计数初值设置波特率9600bpsTH2 = 0xff;//装载固定初值RCAP2L = 0xdc;RCAP2H = 0xff;break;//bps9600case 3:TL2 = 0xee;//计数初值设置波特率19200bpsTH2 = 0xff;//装载固定初值RCAP2L = 0xee;RCAP2H = 0xff;break;//bps19200case 4:TL2 = 0xfa;//计数初值设置波特率57600bpsTH2 = 0xff;//装载固定初值RCAP2L = 0xfa;RCAP2H = 0xff;break;//bps57600case 5:TL2 = 0xfd;//计数初值设置波特率115200bpsTH2 = 0xff;//装载固定初值RCAP2L = 0xfd;RCAP2H = 0xff;break;//bps115200default://默认bps9600TL2 = 0xdc;//计数初值设置波特率9600bpsTH2 = 0xff;//装载固定初值RCAP2L = 0xdc;RCAP2H = 0xff;break;//bps9600}TR2 = 1;//启动定时器2}//串口发送数据void UART_Send_1Byte_Data(unsigned char DAT){while(flag_tx);//等待之前的数据发送完成flag_tx=1;SBUF = DAT;//如果使用while(!TI);//可能会出现TI=1时刚好进入串口中断,然后串口中断将TI=0;此时程序会卡死在while里的}//串口发送字符串void UART_Send_string(unsigned char *c){do{UART_Send_1Byte_Data(*c++);//带*c表示的是值,c表示的是地址}while (*c != '');}//串口中断函数,中断号4//单片机串口只缓存1字节8位数据void UART_IT(void) interrupt 4{static unsigned char num=0;if (TI) //发送标志位{TI = 0;flag_tx=0;//使用printf()/puts()/putchar()(stdio.h)的时候,需要ES=0;TI=1;printf();(TI=0,printf使用后会自动清除)最后ES=1。}if (RI) //接收标志位{RX[num]=SBUF;//将接收的数据先保存起来RI = 0;if(RX[num]=='n'){num=0;flag_rx = 1;//数据接收完毕同样可以发送数据了}else {num++;if(num==2)flag_rx = 1;//可以开始发送数据了}}}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。