串口驅(qū)動程序?qū)嶒?/b>
一.實驗?zāi)康?br>本示例程序展示了如何在Small RTOS51 中編寫串口通信驅(qū)動程序。
二.實驗設(shè)備及器件
IBM PC 機 一臺
DP-51PROC 單片機綜合仿真實驗儀 一臺
三.實驗步驟
1. 將A2 區(qū)的A0~A2 分別連接到B3 區(qū)的A0~A2。
2. 將A2 區(qū)的P10 連接到B3 區(qū)的RST。
3. 將A3 區(qū)的Y0 連接到B3 區(qū)的/CS。
4. 將A2 區(qū)的A15~A10 分別連接到A3 區(qū)的相關(guān)控制引腳, 如下:
A15 --- /G2B
A14 --- /G2A
A13 --- G1
A12 --- C
A11 --- B
A10 --- A
5. 在B3 區(qū)的J92 插入圖形液晶模塊(單色,128×64 點)。
6. 將B3 區(qū)的J85 短接,A3 區(qū)的JP4 短接。
7. 將程序下載到實驗儀中,打開串口調(diào)試窗口設(shè)置波特率為4800b/s 8 位數(shù)據(jù)
位和1 位停止位,在輸入框中寫入數(shù)據(jù):
F0 F1 01 1E
按16 進制方式向?qū)嶒瀮x發(fā)送數(shù)據(jù),LCD 將會顯示1。
PC 機向?qū)嶒瀮x發(fā)送數(shù)據(jù)的通信協(xié)議:
0xf0+0xf1+要顯示的數(shù)據(jù)(1 字節(jié))+ 校驗和(1 字節(jié))
四.實驗參考程序主要部分
#include "config.h"
//指針的NULL 為0,這個變量占用0 地質(zhì)避免出現(xiàn)有效的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); //發(fā)送一個字節(jié)
void Send(uint8 Data); //發(fā)送一個數(shù)據(jù)包
void Recuve(void);
void Command(void);
void TimeSum(void);
/*************************************************************
** 函數(shù)名稱: main
** 功能描述: 主函數(shù),用戶程序從這里執(zhí)行
***************************************************************/
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 進入休眠狀態(tài) */
}
}
/**********************主任務(wù)**********************************/
/************************************************************
** 函數(shù)名稱: command
** 功能描述: 命令處理任務(wù),高層命令由這個任務(wù)執(zhí)行,相當(dāng)于應(yīng)用程序
****************************************************************/
void Command(void)
{
uint8 data temp;
while (1)
{
OSQPend(&temp,CommandData,0);
/* 把接收到的數(shù)據(jù)在LED 數(shù)碼顯示器上顯示出來 */
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');
}
/* 把接收到的數(shù)據(jù)發(fā)送回去 */
Send(temp);
}
}
/**********************串行通訊***********************************/
bit SerialCanSend = 1;
/*******************************************************
** 函數(shù)名稱: 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;
}
/*******************************************************************
** 函數(shù)名稱: Send
** 功能描述: 發(fā)送一個數(shù)據(jù)包
**********************************************************/
void Send(uint8 Data)
{
PutChar(STARTBYTE1);
PutChar(STARTBYTE2);
PutChar(Data);
PutChar(-(STARTBYTE1 + STARTBYTE2 + Data));
}
/****************************************************************
** 函數(shù)名稱: PutChar
** 功能描述: 發(fā)送一個字節(jié)
****************************************************************/
void PutChar(uint8 Data)
{
OS_ENTER_CRITICAL();
if (SerialCanSend == 1)
{
SerialCanSend = 0;
SBUF = Data;
}
else
{
OSQIntPost(SerialOutData,Data);
}
OS_EXIT_CRITICAL();
}
/***************************************************************
** 函數(shù)名稱: Recuve
** 功能描述: 串口接收處理任務(wù)
*************************************************************/
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); /* 接收一個字節(jié) */
/* 處理通信協(xié)議 */
while (1)
{
OSQPend(&temp1,SerialInData,0); /* 接收一個字節(jié) */
if ((temp == STARTBYTE1) && (temp1 == STARTBYTE2))
{
break; /* 接收到起始字符 */
}
temp = temp1;
}
Sum = STARTBYTE1 + STARTBYTE2;
OSQPend(&temp1,SerialInData,0); /* 接收數(shù)據(jù) */
Sum += temp1;
OSQPend(&temp,SerialInData,0); /* 接收校驗和 */
Sum += temp;
if (Sum == 0) /* 檢驗接收到的數(shù)據(jù)包 */
{ /* 發(fā)送消息給主任務(wù) */
OSQPost(CommandData,temp1);
}
}
}
/**************************************************************
** 函數(shù)名稱: comm
** 功能描述: 串口中斷處理程序
*********************************************************/
#pragma disable /* 除非最高優(yōu)先級中斷,否則,必須加上這一句 */
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;
}
}
}
/*********************************************************
** 函數(shù)名稱: 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 秒 */
}
}
五.實驗例程序簡析
由于通信協(xié)議千變?nèi)f化,不同的協(xié)議有不同的適用范圍,不可能給出一個通用的串行
通信協(xié)議驅(qū)動程序,只能給出一個例子。讀者可以根據(jù)本實驗例程的思路寫出符合自己需要
的獨特的通信驅(qū)動程序。本例驅(qū)動程序使用的通信協(xié)議如下:
(1) 波特率為4800,有一個起始位、8 個數(shù)據(jù)位合1 個停止位。
(2) 數(shù)據(jù)包長度為4 個字節(jié)。讀者只需自行改造程序,把數(shù)據(jù)包長度增加后就可以
在實際中使用了。
(3) 起始字節(jié)為STARTBYTE1 、STARTBYTE2 , 中間字節(jié)不可能連續(xù)出現(xiàn)
STARTBYTE1、STARTBYTE2。在實際應(yīng)用中,如果只是發(fā)送命令,就完全可
以避免;如果是發(fā)送數(shù)據(jù),就可能要加轉(zhuǎn)義字符了,此時,起始字符其時可以
只要一個字符。
(4) 數(shù)據(jù)段為一個字符。讀者增加數(shù)據(jù)包長度時應(yīng)同時增加這個字段長度。
(5) 校驗字段為一個字符。加上這個字符后使得整個數(shù)據(jù)包(包括起始字節(jié))按照
字節(jié)依次加起來的和為0。注意這是算術(shù)加而不是邏輯加(異或)。
(6) 不提供握手,握手由用戶程序提供。
本實驗例程獨立使用一個任務(wù)來處理串口通信協(xié)議,這個任務(wù)就是串口接收任務(wù)
(Recuve),其工作流程如下圖5.3 所示:
評論
查看更多