一般我们玩单片机都要研究串口,串口一开始最头痛的无非就是波特率和中断
波特率初始化可以用STC-ISP生成代码,比如STC15W408AS这一款单片机,只有串口0和串口2,需要波特率9600,则可以在STC-ISP中输入如下参数
点击生成C代码,即可自动生成如下代码
void UartInit(void) //9600
{
SCON = 0x50; //sfr SCON = 0x98;
AUXR |= 0x04; //sfr AUXR = 0x8E;
T2L = 0xE0; //sfr T2L = 0xD7;
T2H = 0xFE; //sfr T2H = 0xD6;
AUXR |= 0x10; //
ES = 1; //sbit ES = IE^4; sfr IE = 0xA8;
}
其实就是调定时器,两个接口速率相同才可以通讯,核心在于T2L和T2H的值,其他的则是选择哪个口哪个定时器什么的(那些位啊选择啊什么的太复杂就不讲了)
如果直接把上面的内容复制进去,可能会有报错,说找不到像SCON ,AUXR这些地址,其实都在头文件里定义好的,如果没有头文件也可以在ISP中找
获取以后包含进来即可
中断函数的编写如下
void Uart() interrupt 4
{
ES=0; //
if (RI)
{
RI=0; //
buffer[First_Int] = SBUF; //
First_Int++; //
if(First_Int > Buf2_Max) //
{
First_Int = 0;
}
}
if (TI)
{
TI=0; //
}
ES=1; //
}
相关的全局变量和定义
typedef unsigned char u8;
typedef unsigned int u16;
u8 First_Int = 0;
#define Buf2_Max 64
xdata u8 buffer[Buf2_Max];
每次TI或者RI检测到1,并且串口中断ES打开,就进入中断,进入中断以后判断是收到信息还是发送信息,收到信息则将信息存入buffer数组,用来存储数据的数组最好用xdata加快速度,当数组满了就退出,发出信息则直接把发送信息位清0,最后再打开中断。
中断的开关速度是非常快的,每次一串信息8位过来,都会立刻触发8次中断,每次中断存一位数据。
全局变量First_Int是用于检测buffer是否满了,满了就清0,初始化为0即可。
以上内容实际上只有接收部分,数据存到buffer以后还有很多事情要做,字符串的处理(这才是核心),数据到达以后怎么存储,怎么判断逻辑,怎么发送等
发送字符串函数UART1_SendString(“你好”);
void UART1_SendString(char *s)
{
while(*s)//
{
UART1_SendData(*s++);//
}
}
void UART1_SendData(u8 dat)
{
ES=0;
SBUF=dat; //sfr SBUF = 0x99;
while(TI!=1);
TI=0; //sbit TI = SCON^1; sfr SCON = 0x98;
ES=1;
}
UART1_SendData函数是发送每一位字符的函数,当发送一串字符串时,调用很多次这个函数。
以下是一个比较简单的发送AT指令并请求返回值的函数,是从泥人模块上扣下来的代码,其实上面的很多代码都是扣泥人的,毕竟人家比较专业,废话不多说,这个函数可以帮助深刻理解上面的内容,比如
Second_AT_Command(”AT”,”OK”,3);
就是向模块发送AT,然后查询模块是否返回包含“OK”这个字符,等待时间为3s。
void Second_AT_Command(u8 *b,u8 *a,u8 wait_time) // typedef unsigned char u8;
{
u8 i;
u8 *c;
c = b; //
CLR_Buf2(); //清除buffer
i = 0;
while(i == 0)
{
if( !Find(a) ) {//while循环中每次发送一次数据,回到这寻找buffer中是否有a字符
if(Timer0_start == 0){
CLR_Buf2();
b = c; //
for (b; *b!='\0';b++){
UART1_SendData(*b);
}
UART1_SendLR();
Times = 0;
shijian = wait_time;
Timer0_start = 1;
}
}else{
i = 1;
Timer0_start = 0;
}
}//while
}
上面的代码比较简单,代码量很少,基本逻辑就是循环中不断使用UART1_SendData发送AT,然后检查buffer中是否有OK,最精彩的地方在于代码控制部分,也是串口收发的核心之一,着重观察Timer0_start值的变化
相关全局变量和函数的定义
void CLR_Buf2(void)
{
u16 k;//typedef unsigned int u16;
for(k=0;k<Buf2_Max;k++) //
{
buffer[k] = 0x00;
}
First_Int = 0; //
}
u8 Find(u8 *a)
{
if(strstr(buffer,a)!=NULL)
return 1;
else
return 0;
}
#include"string.h"
bdata u8 Flag;
sbit Timer0_start = Flag^0;
u8 shijian=0,Times = 0;
#define UART1_SendLR() UART1_SendData(0X0D);UART1_SendData(0X0A)
总结一下串口使用,先用keil新建一个工程,然后到STC-ISP中获取头文件,再用ISP生成初始化串口函数,写中断用来存数据,写发送函数。之后就根据自己需求定制了,基本上最难的就是这部分,代码控制和逻辑,比如我使用TLSR8266时,由于要求比较简单,基本上只有一个功能,所以只写了一点点
void main(void)
{
int io1=0,key1;
UartInit();
EA=1; //sbit EA = IE^7; sfr IE = 0xA8;
while(1){
if(KEY)key1 = 1;
if(KEY==0&&key1){
key1 = 0;
if(io1==0){
io1=1;
Second_AT_Command("AT+IO1=L","OK",3);
}else{
io1=0;
Second_AT_Command("AT+IO1=H","OK",3);
}
}
}
}
如果是弄GPS定位之类比较大型的代码,则需要更多对字符串操作函数的掌握和使用,如strtok分割字符串,strcmp字符串匹配函数,strcat字符串追加函数,以及最重要的代码控制,说白了串口使用还是对C的学习。