一、实验目的 1.掌握单片机串行口通信的程序设计,及简易三线式通讯的方法。
2.了解实现串行通讯的硬环境、数据格式的协议、数据交换的协议。
3.学习串口通讯的中断方式的程序编写方法。
4.进一步熟悉利用 PROTEUS、Keil uVision5 等软件进行单片机系统仿真设计的方法。
二、实验任务
1.基本任务
(1)已知甲机接 8 个开关,乙机接 8 个发光二极管,利用它们的串口方式 1,波
特率自定义,实现:将甲机中 8 个开关所代表的数据传送到乙机,并在乙机的 8 个 LED
灯显示。请在 Proteus 中画出电路原理图,并编写程序仿真实现上述功能。
(2)已知单片机的 P0 口接了 8 个发光二极管 LED0~LED7,现要求通过单片机的
串口收发上位机的命令,实现对这 8 个发光二极管的控制。PC 端采用串口调试程序进
行数据发送(如使用 stc-isp 烧写软件向单片机发送“88 FB AF XX FC FC”6 个字节的
命令,其中“88 FB AF”及“FC FC”为数据的帧头和帧尾,“XX”为 00~07 数据。 )单片机
使用串口中断进行数据接收,同时需要判断帧头和帧尾的正确性。判断帧头和帧尾完毕
后,若正确的话再判断“XX” 数据,对应“XX” 数据对 LED0~LED7 进行点亮、熄灭控
制;若不正确丢掉数据, 转入等待接收。 请在 Proteus 中画出电路原理图,并编写程
序仿真实现上述功能。
2.拓展任务
在以上基本任务 1 的基础上,奇校验,实现甲机和乙机的全双工通信,即甲机和乙
机都分别接 8 个开关和 8 个发光二极管,甲机 8 个开关所代表的数据能传送到乙机并在
乙机的 8 个 LED 灯显示,同时乙机 8 个开关所代表的数据能传送到甲机并在甲机的 8
个 LED 灯显示,若校验出错则指示灯(自定义)闪烁。请在 Proteus 中画出电路原理图,
并编写程序仿真实现上述功能。
//-----------------------发送端---------------------------//
#include "STC15.H"
bit busy=0;
//-----------------------串口初始化子函数-------------------------//
void Uart1_Init(void) //9600bps@11.0592MHz
{
SCON = 0x40; //8位数据,可变波特率 方式1
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1; //启动串口中断
}
//-----------------------数据发送子函数---------------------------//
void SendData(unsigned char dat)
{
while(busy);
SBUF=dat;
busy=1;
}
//---------------------------中断函数------------------------------//
void UART1_isr (void) interrupt 4
{
if(TI)
{
TI=0; //清除标志位
busy=0; //清除忙标志位
}
}
//---------------------------主函数------------------------------//
void main()
{
Uart1_Init(); //串口初始化
EA=1; //打开总中断
while(1)
{
SendData(P1); //发送P1口数值
}
}
//-----------------------接收端---------------------------//
#include "STC15.H"
unsigned int temp;
//-----------------------串口初始化子函数-------------------------//
void Uart1_Init(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率 REN=1处于接受状态
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1; //启动串口中断
}
//-------------------------中断函数------------------------------//
void UART1_isr (void) interrupt 4
{
if(RI)
{
RI=0; //标志位清0
temp=SBUF; //数据暂存
P0=temp; //P0接收发送端数据
}
}
//---------------------------主函数------------------------------//
void main()
{
Uart1_Init(); //串口初始化
EA=1; //打开总中断
while(1);
}
#include "stc15.h"
#define uchar unsigned int //对数据类型进行声明定义
volatile bit Flag=0;
uchar i,val;
uchar arr[6];
//-----------------------串口初始化子函数-------------------------//
void Uart1_init() //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不加倍控制/帧错误检测
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES=1; // 串口1中断打开
EA=1; //全局中断使能
}
//---------------------------中断函数------------------------------//
void Uart1_INT() interrupt 4
{
ES=0; //串口1中断关闭
if(RI)
{
Flag=1; //接收到数据,接收标识符有效
RI=0; //串口接收标志位清0
arr[i]=SBUF; //将接收到的数据赋给数组中判断
if(arr[i]==0x88) //判断数组
{
arr[0]=arr[i];
i=0;
}
i++;
if(i==6)
{
i=0;
if(arr[0]==0x88&&arr[1]==0xFB&&arr[2]==0xAF&&arr[4]==0xFC&&arr[5]==0xFC)
{
val=arr[3];
switch (val)
{
case 0x00:P0=0XFE;break;
case 0x01:P0=0XFD;break;
case 0x02:P0=0XFB;break;
case 0x03:P0=0XF7;break;
case 0x04:P0=0XEF;break;
case 0x05:P0=0XDF;break;
case 0x06:P0=0XBF;break;
case 0x07:P0=0X7F;break;
}
}
}
}
ES=1; // 串口1中断打开
}
//---------------------------主函数------------------------------//
void main()
{
Uart1_init(); //串口初始化
while(1); //循环运行
}
#include "stc15.h"
#include "intrins.h"
volatile bit Flag=1;
//---------------------------延时函数------------------------------//
void Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 7;
j = 78;
k = 167;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//-----------------------串口初始化子函数-------------------------//
void Uart1_Init(void) //9600bps@11.0592MHz
{
SCON = 0x90; //9位数据,方式2,可变波特率,带TB8/RB8奇偶校验位
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0xE0; //设定定时初值
TH1 = 0xFE; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1; //使能串口中断
EA=1; //全局中断使能
}
//-------------------------数据发送函数-----------------------------//
/*********************************************************************
* 由于PSW中的P可以表达累加器ACC中“1”的个数奇偶性,P=1,A中“1”的个数为 *
* 奇数,P=0,A中“1”的个数为偶数 *
*********************************************************************/
void Send_Data(unsigned char dat)
{
ACC=dat; //将数据赋给累加器ACC
TB8=P; //发送从累加器得到的第9位数据
SBUF=dat; //发送数据到数据缓冲器
while(TI==0);//当TI标志位等于零时
TI=0; //TI标志位清零
}
//-------------------------数据传送函数-----------------------------//
void UART1_Puts(void)
{
if(Flag)
{
ES=0; //串口1中断关闭
Send_Data(P1); //发送P1接收到的数据
ES=1; //串口1中断开启
Flag=0; //清除接收标识符
}
}
//---------------------------中断函数------------------------------//
void Uart1_Isr(void) interrupt 4
{
ES=0; //串口1中断关闭
if(RI) //RI为1,接收数据
{
RI=0; //RI标志位清零
Flag=1; //接收到数据,接收标识符有效
if(RB8==1) //接收第9位数据校验结果是否为奇数
{
P0=SBUF; //将接收到的数据赋给P0端
}
else //校验结果不为奇数时,出错执行P0端LED全亮全灭
{
P0=0x00;
Delay150ms();
P0=0xFF;
Delay150ms();
}
}
if(TI) //TI为1,发送数据
{
TI=0; //TI标志位清零
}
ES=1; //串口1中断打开
}
//---------------------------主函数------------------------------//
void main()
{
Uart1_Init(); //串口初始化
while(1) //循环运行
{
UART1_Puts(); //数据传送
}
}
来源:oschina
链接:https://my.oschina.net/u/4325464/blog/4325743