实验笔记:串行口
单片机与计算机或同一板卡上的其它外围芯片传输数据的过程称为通信。
单片机与计算机最常用的通信方式是RS232串口通信和USB通信。
单片机与外围芯片最常用的通信方式是SPI与I2C通信。
RS232串口通信使用3条线:
数据发送TXD、数据接收RXD和公共地线GND
USB通信使用4条线:
数据D+、数据D-、电源VCC和公共地线GND
SPI通信使用4条线:
串行时钟SCLK、串行数据输出MOSI、串行数据输入MISO、和公共地线GND。
对于SPI通信,当在同一传输线上挂接有多个器件时,可以通过增加片选线的方式选择指定的目标器件进行数据传输。
I2C通信使用3条线:
时钟CLK、串行数据SDA和公共地线GND
I2C通信传输的数据中有目标器件的地址信息,因此没有片选线。
RS232接口数据发送线与接收线并存,在传输过程中容易产生干扰,因此,要求两条信号线平行排列。不能使用双绞线,理论传输距离15米。
串口1控制寄存器SCON
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位名称 | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
|
|
|
|
|
|
|
|
|
SM0 SM1:方式 串行口工作方式选择位
0 0 0 移位寄存器方式,用于普通电路的串并转换(一般不用)
0 1 1 格式固定的10位串口通信(最常用)
1 0 2 格式固定的11位串口通信(用于奇偶校验或多机通信,一般不用)
1 1 3 格式固定的11位串口通信(用于奇偶校验或多机通信,一般不用)
SM2:多机通信控制位
REN:确定是否允许串口接收数据,REN=1允许,REN=0禁止
TB8:方式2、3发送数据前通过编写程序将待发送的第9位(奇偶校验位)放到这里来;
对于方式0和方式1,直接将TB8设为0。由于奇偶校验过于简单,不具备真正的数据传输错误检测能力,因此被实际应用中的“校验和”与“CRC校验”所取代。
RB8:方式2、3接收到的第9位,即奇偶校验位。
TI:一帧数据发送结束后由硬件产生的中断请求标志,只能通过软件清零
RI:接收中断标志,串口接收电路自动接收完一帧数据后,由硬件置1,只能通过软件清零
与串口1相关的电源控制寄存器PCON
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位名称 | SMOD | SMOD0 | LVDF | POF | GF1 | GF0 | PD | IDL |
|
|
|
|
|
|
|
|
|
SMOD:用于设置串口1的工作方式1---3的波特率是否加倍,其它串口波特率与此寄存器无关。
0:各工作方式的波特率不加倍
1:串口1的工作方式1---3的波特率加倍
SMOD0:用于帧错误检测,无实用价值,PCON的其他各位与串口通信无关。
关于波特率:
波特率:就是每秒传输的数据的位数,单位是bps。
假设数据传送的波特率为115200bps,采用N,8,1帧格式(10位),则每秒传送字节数为115200/10=11520,传送一个字节所需要的时间是1/11520=86.8us,就是说,移位寄存器接收到1字节需要的时间是86.8us,这就要求CPU在接收到串口中断申请(RI=1)后的86.8us内取走SBUF中的数据,否则前一帧数据就将被覆盖。
单片机与计算机通信的例子:
例1:单片机向计算机发送0---255范围内不断增大的数据,使用串口1,定时器T1作为波特率发生器,波特率为9600bps,系统时钟频率为11.0592MHz。单片机串口1接收引脚是RXD/3.0,发送引脚是TXD/3.1,也就是默认的程序下载引脚。
#include "STC15W4K.H"
#define uchar unsigned char
void delay500ms()
{
unsigned char i,j,k; // i,j,k由由软件计算出并验证正确。
for(i=41;i>0;i--) // 注意后面没分号
for(j=133;j>0;j--) // 注意后面没分号
for(k=252;k>0;k--); // 注意后面有分号
}
//串行口初始化
void UART_init(void)
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xDC; //设定定时初值
TH1 = 0xDC; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
void UART_send_byte(uchar dat)
{
SBUF=dat;
while(!TI); //如果一个字节的数据未发送完,则等待
TI=0; //清除中断标志
}
//主函数入口
void main()
{
uchar idata num=0;
UART_init(); //串行口初始化
while(1)
{
UART_send_byte(num++);
delay500ms();
}
}
例2:单片机接收计算机的数据,加1后发回计算机,使用串口1,定时器T2作为波特率发生器,波特率为9600bps,系统时钟频率为11.0592MHz。
#include "STC15W4K.H"
#define uchar unsigned char
//串行口初始化
void UART1_init(void)
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器T2为波特率发生器
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0xE0; //设定定时初值
T2H = 0xFE; //设定定时初值
AUXR |= 0x10; //启动定时器2
EA=1;
ES=1;
}
void UART1(void) interrupt 4 //串行口1中断函数
{
uchar idata num=0;
if(TI) //如果发生发送中断
{
TI=0; //软件清标志
}
if(RI) //如果发生接收中断
{
RI=0;
num=SBUF;
num++;
SBUF=num;
}
}
//主函数入口
void main()
{
UART1_init(); //串行口初始化
while(1)
{ ; }
}
例3:单片机接收计算机数据,加1后发回计算机。使用串口2,波特率为9600,系统时钟SYSclk=11.0592MHz。
#include "STC15W4K.H"
#define uchar unsigned char
void delay500ms()
{
unsigned char i,j,k; // i,j,k由由软件计算出并验证正确。
for(i=41;i>0;i--) // 注意后面没分号
for(j=133;j>0;j--) // 注意后面没分号
for(k=252;k>0;k--); // 注意后面有分号
}
//串行口初始化
void UART2_init(void)
{
S2CON = 0x10; //8位数据,可变波特率
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0xE0; //设定定时初值
T2H = 0xFE; //设定定时初值
AUXR |= 0x10; //启动定时器2
EA=1;
IE2=1; //开串口中断2
}
void UART_send_byte(uchar dat)
{
SBUF=dat;
while(!TI); //如果一个字节的数据未发送完,则等待
TI=0; //清除中断标志
}
void UART2(void) interrupt 8 //串行口1中断函数
{
uchar idata num=0;
if( S2CON & 0x02 ) // 如果发生发送中断
{
S2CON&=0xFD; //软件清标志
}
if( S2CON & 0x01 ) //如果发生接收中断
{
S2CON&=0xFE;
num=S2BUF;
num++;
S2BUF=num;
}
}
//主函数入口
void main()
{
UART2_init(); //串行口初始化
while(1) {;}
}
UART2的输出口是RxD2—P1.0 TxD2---P1.1
联系客服