目录
一、相关知识
1.串行通信
2.串行通信制式
3.串行通信的主要方式
4.波特率
5.波特率的计算公式
6.串口控制寄存器
7.UART口数据的发送和接收
二、所要实现的功能
三、代码实现
1.参数定义
2.138译码器通道选择函数
3.初始化系统
4.串口初始化函数
5.串口发送函数
6.串口接收函数
7.完整代码
四、运行图片
关于中断以及定时器都在之前的文章中介绍过了,此处不再介绍了。
一、相关知识
1.串行通信
微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,分为并行通信和串行通信。所谓并行通信,是指数据的各位同时发送或接收,每个数据使用一条导线;串行通信,是指数据一位一位地按顺序发送或接收。
串行通信有SPI、IIC、UART等多种,最常见最通用的是指UART,大多数情况下,串口通信指的就是UART。
2.串行通信制式
串行通信的制式有三种:①单工。两个设备之间只有一个方向,要么只能收数据,要么只能发数据;②半双工。两个设备之间可以发数据也可以收数据,但是在同一时刻只能有一种状态;③全双工。既可以发送也可以接收而且两者可以同时进行。
该单片机使用的RS485总线是半双工的通信制式。
3.串行通信的主要方式
串行通信的方式主要有两种:同步和异步。
同步串行通信:需要使用同一个时钟,以数据块为单位传送数据;异步串行通信:每个设备都有自己的时钟信号,通信双方的波特率要保持一致,以字符为单位进行数据帧传送,一次传送一帧。
4.波特率
波特率为串口每秒钟传输的位数。
在51单片机的串口通信中,模式1和模式3的波特率是可变的,取决于定时器1的溢出率,也就是说定时器1每溢出一次,串口就发送一次数据。
通常使用定时器1的工作模式2(8位自动重装载)来产生波特率。TL1作为脉冲计数寄存器,TH1作为自动重装载寄存器,当计数到最大值溢出时,TH1的值会自动装到TL1中。
5.波特率的计算公
6.串口控制寄存器
7.UART口数据的发送和接收
串行口中有两个缓冲寄存器SBUF,一个是发送寄存器,一个是接收寄存器。在物理结构上是完全独立的,他们都是字节寻址的寄存器,字节地址为99H。
这个重叠的地址靠读、写指令来区分。串行发送时,CPU向SBUF写入数据,此时99H表示发送缓存SBUF;串行接收时,CPU从SBUF读出数据,此时99H表示接收缓存SBUF。
数据发送,把数据放进SBUF之后,内核会自动把数据发送出去,内容发送完成后,会将标志位TI置为1;数据接收,内核从串口接收到一个完整的数据之后,会将标志位RI置为1,用户从SBUF直接读取即可。
总的来说就是,我们读取的时候读取的是SBUF里面的备份数据,读取之后SBUF里面的内容并不会消失。
注意:标志位TI和RI需要我们用软件来实现清零。对于IAP15F2K61S2单片机,还需要对辅助寄存器AUXR(0x8e)进行配置。直接置为0即可。
二、所要实现的功能
实现在波特率为9600b/s时,单片机向上位机stc-isp发送两位数字。
三、代码实现
1.参数定义
// 参数定义
unsigned char get_dat = 0x00;
2.138译码器通道选择函数
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = ( P2 & 0x1f ) | 0x00; // 0
break;
case 4:
P2 = ( P2 & 0x1f ) | 0x80; // Y4C
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0; // Y5C
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0; // Y6C
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0; // Y7C
break;
}
}
3.初始化系统
// 初始化系统
void System_Init(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
// 关闭通道选择
HC138_Init( 0 );
}
4.串口初始化函数
// 串口初始化
void UART_Init(void)
{
TMOD = 0x20; // 通常使用定时器1工作模式2(8位自动重装载)
// 不能再开启定时器1的中断,就让它做波特率发生器,开中断可能会影响串口数据的发送
// ET1 = 1;
EA = 1;
TR1 = 1;
TH1 = 0xfd; // 波特率9600b/s所对应的TH1和TL1
TL1 = 0xfd;
SCON = 0x50; // 串口通信模式1,允许接收控制
ES = 1;
AUXR = 0x00; // 辅助寄存器,直接置为0
}
5.串口发送函数
// 串口发送信息
void UART_Send( unsigned char dat )
{
/*
先把数据传给SBUF,while( TI == 0 )必须写在中间,不能写在第一个,否则发送不出去数据。
不管TI是否置为1了,都把数据传给SBUF,等待置为1的时候立马收到数据。
如果while放在前面那么TI置为1之后一瞬间把值传给SBUF,然后TI立马置为0,系统会反应不过来,就发送不出去。
*/
SBUF = dat; // 接收到消息就传给SBUF
while( TI == 0 ); // 还未收到消息的时候执行空指令
TI = 0; // 接收到消息后接收中断标志位TI=1,需要软件手动置零
}
6.串口接收函数
// 串口接收信息
void UART_Receive() interrupt 4
{
if( RI == 1 ) // 接收标志位置为1,表示收到了
{
RI = 0;
get_dat = SBUF;
UART_Send( get_dat ); // 接收到再发出去,发送给上位机,才能显示出来
}
}
7.完整代码
#include <STC15F2K60S2.H>
// 参数定义
unsigned char get_dat = 0x00;
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = ( P2 & 0x1f ) | 0x00; // 0
break;
case 4:
P2 = ( P2 & 0x1f ) | 0x80; // Y4C
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0; // Y5C
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0; // Y6C
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0; // Y7C
break;
}
}
// 初始化系统
void System_Init(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
// 关闭通道选择
HC138_Init( 0 );
}
// 串口初始化
void UART_Init(void)
{
TMOD = 0x20; // 通常使用定时器1工作模式2(8位自动重装载)
// 不能再开启定时器1的中断,就让它做波特率发生器,开中断可能会影响串口数据的发送
// ET1 = 1;
EA = 1;
TR1 = 1;
TH1 = 0xfd; // 波特率9600b/s所对应的TH1和TL1
TL1 = 0xfd;
SCON = 0x50; // 串口通信模式1,允许接收控制
ES = 1;
AUXR = 0x00; // 辅助寄存器,直接置为0
}
// 串口发送信息
void UART_Send( unsigned char dat )
{
/*
先把数据传给SBUF,while( TI == 0 )必须写在中间,不能写在第一个,否则发送不出去数据。
不管TI是否置为1了,都把数据传给SBUF,等待置为1的时候立马收到数据。
如果while放在前面那么TI置为1之后一瞬间把值传给SBUF,然后TI立马置为0,系统会反应不过来,就发送不出去。
*/
SBUF = dat; // 接收到消息就传给SBUF
while( TI == 0 ); // 还未收到消息的时候执行空指令
TI = 0; // 接收到消息后接收中断标志位TI=1,需要软件手动置零
}
// 串口接收信息
void UART_Receive() interrupt 4
{
if( RI == 1 ) // 接收标志位置为1,表示收到了
{
RI = 0;
get_dat = SBUF;
UART_Send( get_dat ); // 接收到再发出去,发送给上位机,才能显示出来
}
}
int main(void)
{
System_Init();
UART_Init();
while(1);
}