本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步!
> 个人主页:@日月同辉,与我共生的博客
> 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。
系列专栏:CSDN-单片机串口通信学习系列🎁
> 我的格言是:“尽最大努力,做最好的自己!💪
转载请提前告知博主!!!
版权声明:本文为CSDN博主「日月同辉,与我共生」的原创文章,CSDN独一份。
目录
一、波特率设置及初值计算
1.1回顾-初值公式
fosc:晶振频率,通常取11.0592Mhz=110592hz。本次设计单片机晶振频率设置为11.0592Mhz。
SMOD:波特率加倍位。SMOD=0时,波特率不变;SMOD=1时,波特率加倍;
波特率:通常取9600bit/s,19200bit/s等。
初值就是定时初始值TH1和定时重载值TL1。
1.2计算初值
本文设计波特率为9600bit/s。波特率为9600bit/s,串口工作方式1,初值结果为253,十六进制为0xFD。
1.3设置波特率
虚拟终端、COMPIM、虚拟串口的波特率统一设置为9600bit/s。
二、初始化
2.1回顾-查询法&中断法
查询法:TI=0时,准备发送;TI=1时,发送完成。所以while(!TI);的作用就是等待发送完成,即发送完成前,TI=0,代码执行会一直执行该语句,发送完成后,TI自动置1,该语句不再执行,开始执行下一条语句。发送完成后,要将TI清0,以便下次能正确发送。
void main()
{
UartInit();//调用串口初始化函数
while(1)
{
SBUF = '0';//发送一帧数据
while(!TI);//等待发送完成(TI会自动置1)
TI=0;//将TI置0
delay(1000);//延时1s
}
}
中断法:要写中断服务函数,当发送完成后,因TI自动置1,所以触发中断服务函数,在中断服务函数中,将TI清0,以便下次能正确发送。串口通信中断入口编号为4。
//发送数据
void main()
{
UartInit();//调用串口初始化函数
while(1)
{
SBUF=0x00;
delay(2000);//延时2s
}
}
//初始化看第二章2.2
//中断服务函数
void ES_timer() interrupt 4 //当TI置1时,会进入中断服务函数
{
if(TI)
{
TI=0;//TI软件置0
}
}
2.2初始化函数
查询法初始化:初始化时,要设置寄存器SCON(工作方式、是否多机通信、数据位数),REN一般要接收(置1),初值就是定时初始值TH1/定时重载值TL1,工作方式为方式1(8位异步重载),波特率可变,因为是8位数据传输,所以定时器为定时器T1工作方式为方式2。中断法设置同上。
void UartInit() //4800bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFA; //设置定时初始值
TH1 = 0xFA; //设置定时重载值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
}
中断法初始化:除了跟查询法一样的设置外,还要打开总中断EA=1,串口中断开关ES=1。
void UartInit(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xFD; //设置定时初始值
TH1 = 0xFD; //设置定时重载值
ET1 = 0; //禁止定时器中断
ES=1;
EA=1;
TR1 = 1; //定时器1开始计时
}
三、发送一帧数据
3.1原理
原理跟查询法一样。第一步:发送数据dat。第二步:等待发送完成。第三步:TI清0。
3.2发送一帧数据函数
void sendByte(unsigned char dat) //发送一帧数据功能函数
{
SBUF=dat;
while(!TI);
TI=0;
}
3.3主程序及结果展示1
void main()
{
UartInit();//调用串口初始化函数
while(1)
{
sendByte(0x88);
delay(2000);
}
}
结果:
四、发送字符串
4.1原理
(1)数组:k常数,定义数组int a[k],a[k]存储了k个元素,数据元素类型为int,a[0]=a0,a[k-1]=a k-1,最末尾有结束符‘\0’。当代码发送到字符等于‘\0’时,说明发送字符串已经完成。
(2)指针:
指针变量:int *p=&a;p是指针变量,存储有a的地址,数据类型为int*。
*和&的区别:*是解引用符,&是地址符。p存储有a的地址,所以*p会根据a的地址找到a的值,即*p=a;
而数组本质上是一个指针常量,使用下标代表每个元素的值,可以用指针代替下标,由指针代表每个元素值。a[]为一个数组,int *p=a;语句*p=a,此时指针默认指向下标0,即*p的值为a[0],语句*p++;可以让指针由原来指向下标0变为指向下标1,即此时*p=a[1]。
4.2发送字符串
void sendString(unsigned char *dat)//发送字符串函数
{
while(*dat != '\0')
{
sendByte(*dat++);
}
}
4.3主程序及结果展示2
void main()
{
UartInit();//调用串口初始化函数
while(1)
{
sendString("hellow world\r\n");
delay(2000);
}
}
结果:
五、printf串口输出重定向
5.1printf函数
printf函数大家比较陌生,这个是#include <stdio.h>里面的库函数。下图是printf函数的格式:
可以看出,不同数据类型格式不同,printf函数发送的是字符串/十进制数,大家可以收藏起来以后说不定会用到!!!
5.2printf串口输出重定向函数
char putchar(char c)
{
sendByte(c);
return c;
}
5.3主程序及结果展示3
void main()
{
unsigned char dat=88;
char a = 1;
int b = 12365;
long c = 0x7FFFFFFF;
unsigned char x = 'A';
unsigned int y = 54321;
unsigned long z = 0x4A6F6E00;
float f = 10.0;
float g = 22.95;
UartInit();//调用串口初始化函数
while(1)
{
printf("hellow world\r\n");
printf("dat=%bu\r\n",dat);
printf ("char %bd int %d long %ld\n",a,b,c);
printf ("Uchar %bu Uint %u Ulong %lu\n",x,y,z);
printf ("%f != %g\n", f, g);
delay(2000);
}
}
结果:
unsigned char dat=88;
printf("hellow world\r\n");//发送到格式hellow world
printf("dat=%bu\r\n",dat);//发送到格式dat=88注:printf函数发送的是十进制数/字符串。
char a = 1;
int b = 12365;
long c = 0x7FFFFFFF;unsigned char x = 'A';
unsigned int y = 54321;
unsigned long z = 0x4A6F6E00;float f = 10.0;
float g = 22.95;printf ("char %bd int %d long %ld\n",a,b,c);
//格式是char 1 int 12365 long 21474(把c转成了十进制)
printf ("Uchar %bu Uint %u Ulong %lu\n",x,y,z);//格式是Uchar 65 Uint 54321 Ulong 1248816640
printf ("%f != %g\n", f, g);//格式是10.000000!=22.95
下一文将着重一帧数据的接收 ,亲爱的读者敬请期待,下一文更精彩!!!
一日不读书,胸臆无佳想。我叫不白吃,喜欢我的,可以支持我,博主名叫@日月同辉,与我共生