串口驱动程序实验
一.实验目的
本示例程序展示了如何在Small RTOS51 中编写串口通信驱动程序。
二.实验设备及器件
IBM PC 机 一台
DP-51PROC 单片机综合仿真实验仪 一台
三.实验步骤
1. 将A2 区的A0~A2 分别连接到B3 区的A0~A2。
2. 将A2 区的P10 连接到B3 区的RST。
3. 将A3 区的Y0 连接到B3 区的/CS。
4. 将A2 区的A15~A10 分别连接到A3 区的相关控制引脚, 如下:
A15 --- /G2B
A14 --- /G2A
A13 --- G1
A12 --- C
A11 --- B
A10 --- A
5. 在B3 区的J92 插入图形液晶模块(单色,128×64 点)。
6. 将B3 区的J85 短接,A3 区的JP4 短接。
7. 将程序下载到实验仪中,打开串口调试窗口设置波特率为4800b/s 8 位数据
位和1 位停止位,在输入框中写入数据:
F0 F1 01 1E
按16 进制方式向实验仪发送数据,LCD 将会显示1。
PC 机向实验仪发送数据的通信协议:
0xf0+0xf1+要显示的数据(1 字节)+ 校验和(1 字节)
四.实验参考程序主要部分
#include "config.h"
//指针的NULL 为0,这个变量占用0 地质避免出现有效的NULL 指针
uint8 OS_Q_MEM_SEL NotUse _at_ 0x0000;
uint8 OS_Q_MEM_SEL CommandData[16]; //给命令消息队列分配的队列空间
uint8 OS_Q_MEM_SEL SerialInData[16]; //给读串口消息队列分配的队列空间
uint8 OS_Q_MEM_SEL SerialOutData[32]; //给写串口消息队列分配的队列空间
void PutChar(uint8 Data); //发送一个字节
void Send(uint8 Data); //发送一个数据包
void Recuve(void);
void Command(void);
void TimeSum(void);
/*************************************************************
** 函数名称: main
** 功能描述: 主函数,用户程序从这里执行
***************************************************************/
void main(void)
{
OSInit();
TMOD = (TMOD & 0XF0) | 0X01;
TH0 = (65536 - (11059200 / 12) / 100) / 256;
TL0 = (65536 - (11059200 / 12) / 100) % 256;
TR0 = 1;
ET0 = 1;
TF0 = 0;
OSSemCreate(ZL12864_SEM, 1);
LCM_DispIni();
OSDispClr();
OSDispStr(1,1, "Start...")
OSTaskCreate(Recuve, NULL, 0);
OSTaskCreate(Command, NULL, 1);
OSTaskCreate(TimeSum, NULL, 2);
while(1)
{
PCON = PCON | 0x01; /* CPU 进入休眠状态 */
}
}
/**********************主任务**********************************/
/************************************************************
** 函数名称: command
** 功能描述: 命令处理任务,高层命令由这个任务执行,相当于应用程序
****************************************************************/
void Command(void)
{
uint8 data temp;
while (1)
{
OSQPend(&temp,CommandData,0);
/* 把接收到的数据在LED 数码显示器上显示出来 */
OSDispChar(3, 5, ' ');
OSDispChar(3, 6, ' ');
OSDispChar(3, 8, ' ');
OSDispChar(3, 9, (temp % 10) + '0');
if (temp >= 10)
{
OSDispChar(3, 8, ((temp / 10) % 10) + '0');
}
if (temp >= 100)
{
OSDispChar(3, 6, (temp / 100) + '0');
}
/* 把接收到的数据发送回去 */
Send(temp);
}
}
/**********************串行通讯***********************************/
bit SerialCanSend = 1;
/*******************************************************
** 函数名称: SerialInit
** 功能描述: 初始化串行口
********************************************************/
void SerialInit(void)
{
SCON = 0x50;
PCON = 0x80;
TMOD = TMOD & 0x0f;
TMOD = TMOD | 0x20;
TH1 = 0xf4; //com is 4800 b/s
TL1 = 0xf4;
TR1 = 1;
ES = 1;
}
/*******************************************************************
** 函数名称: Send
** 功能描述: 发送一个数据包
**********************************************************/
void Send(uint8 Data)
{
PutChar(STARTBYTE1);
PutChar(STARTBYTE2);
PutChar(Data);
PutChar(-(STARTBYTE1 + STARTBYTE2 + Data));
}
/****************************************************************
** 函数名称: PutChar
** 功能描述: 发送一个字节
****************************************************************/
void PutChar(uint8 Data)
{
OS_ENTER_CRITICAL();
if (SerialCanSend == 1)
{
SerialCanSend = 0;
SBUF = Data;
}
else
{
OSQIntPost(SerialOutData,Data);
}
OS_EXIT_CRITICAL();
}
/***************************************************************
** 函数名称: Recuve
** 功能描述: 串口接收处理任务
*************************************************************/
void Recuve(void)
{
uint8 data temp,temp1;
uint8 Sum;
/* 建立所需要的消息队列 */
OSQCreate(CommandData,16);
OSQCreate(SerialInData,16);
OSQCreate(SerialOutData,32);
SerialInit(); /* 初始化串行口 */
while (1)
{
OSQPend(&temp,SerialInData,0); /* 接收一个字节 */
/* 处理通信协议 */
while (1)
{
OSQPend(&temp1,SerialInData,0); /* 接收一个字节 */
if ((temp == STARTBYTE1) && (temp1 == STARTBYTE2))
{
break; /* 接收到起始字符 */
}
temp = temp1;
}
Sum = STARTBYTE1 + STARTBYTE2;
OSQPend(&temp1,SerialInData,0); /* 接收数据 */
Sum += temp1;
OSQPend(&temp,SerialInData,0); /* 接收校验和 */
Sum += temp;
if (Sum == 0) /* 检验接收到的数据包 */
{ /* 发送消息给主任务 */
OSQPost(CommandData,temp1);
}
}
}
/**************************************************************
** 函数名称: comm
** 功能描述: 串口中断处理程序
*********************************************************/
#pragma disable /* 除非最高优先级中断,否则,必须加上这一句 */
void comm(void) interrupt 4
{
uint8 data temp;
if (RI == 1)
{
OS_INT_ENTER();
RI = 0;
OSQPost(SerialInData,SBUF);
OSIntExit();
return;
}
if (TI == 1)
{
TI = 0;
if (OSQAccept(&temp,SerialOutData) == OS_Q_OK)
{
SBUF = temp;
}
else
{
SerialCanSend = 1;
}
}
}
/*********************************************************
** 函数名称: TimeSum
** 功能描述: 在LCD 中显示“: ”,并闪烁
****************************************************************/
void TimeSum(void)
{
while (1)
{
OSDispChar(3, 7, ':');
OSWait(K_TMO,OS_TICKS_PER_SEC / 2); /* 延时0.5 秒 */
OSDispChar(3, 7, ' ');
OSWait(K_TMO,(OS_TICKS_PER_SEC + 1) / 2); /* 延时0.5 秒 */
}
}
五.实验例程序简析
由于通信协议千变万化,不同的协议有不同的适用范围,不可能给出一个通用的串行
通信协议驱动程序,只能给出一个例子。读者可以根据本实验例程的思路写出符合自己需要
的独特的通信驱动程序。本例驱动程序使用的通信协议如下:
(1) 波特率为4800,有一个起始位、8 个数据位合1 个停止位。
(2) 数据包长度为4 个字节。读者只需自行改造程序,把数据包长度增加后就可以
在实际中使用了。
(3) 起始字节为STARTBYTE1 、STARTBYTE2 , 中间字节不可能连续出现
STARTBYTE1、STARTBYTE2。在实际应用中,如果只是发送命令,就完全可
以避免;如果是发送数据,就可能要加转义字符了,此时,起始字符其时可以
只要一个字符。
(4) 数据段为一个字符。读者增加数据包长度时应同时增加这个字段长度。
(5) 校验字段为一个字符。加上这个字符后使得整个数据包(包括起始字节)按照
字节依次加起来的和为0。注意这是算术加而不是逻辑加(异或)。
(6) 不提供握手,握手由用户程序提供。
本实验例程独立使用一个任务来处理串口通信协议,这个任务就是串口接收任务
(Recuve),其工作流程如下图5.3 所示:
评论
查看更多