📄 ext5.c
字号:
/*********************************************************************************************************
** Small RTOS(51)
** The Real-Time Kernel(For Keil c51)
**
** (c) Copyright 2002-2003, chenmingji
** All Rights Reserved
**
** V1.20.0
**
**
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名: ext1.c
**创 建 人: 陈明计
**最后修改日期: 2003年8月3日
**描 述: ext1源代码。
**
**--------------历史版本信息----------------------------------------------------------------------------
** 创建人: 陈明计
** 版 本: V0.50
** 日 期: 2002年2月22日
** 描 述: 原始版本
**
**------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 版 本: V1.11.0
** 日 期: 2003年12月2日
** 描 述: 删除TaskD代码
**
**------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 版 本: V1.12.0
** 日 期: 2003年12月2日
** 描 述: 无变化
**
**------------------------------------------------------------------------------------------------------
** 修改人: 陈明计
** 版 本: V1.20.0
** 日 期: 2003年8月3日
** 描 述: 根据新版本要求修改
**
**--------------当前版本修订------------------------------------------------------------------------------
** 修改人: Crossmind
** EDNChian 博客 http://www.ednchina.com/Blog/crossmind/
** 日 期: 2008-3-22
** 描 述: Protues 7.2 + EDNCHINA 51仿真板
** 功能描述:
EX5: 一个稍微复杂的例子
【详细内容请参见博客中的文章】 其他EX:
EX1: 创建3个任务,分别闪烁三颗 LED 【练习重点:创建任务】
EX2: 创建3个任务,分别向LCD随机位置写入字符"A","B","C" 【练习重点:LCD驱动程序】
EX3: 数据采集、处理及显示 【练习重点:信号量使用】
EX4: 按键任务,【练习重点:任务消息使用】
** EX系列将不断增加
更多关于SmallRTOS的内容请到我的博客:http://www.ednchina.com/Blog/crossmind/
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#include "config.h"
uint8 OS_Q_MEM_SEL NotUse _at_ 0x0000; //指针的NULL为0,这个变量占用0地质避免出现有效的NULL指针
uint8 OS_Q_MEM_SEL CommandData[16]; //给命令消息队列分配的队列空间
uint8 OS_Q_MEM_SEL SerialInData[16]; //给读串口消息队列分配的队列空间
uint8 OS_Q_MEM_SEL SerialOutData[32]; //给写串口消息队列分配的队列空间
#define LCDSem 0 //共享资源LCD互斥信号量
#define TEMPSem 1 //测温度任务启动信号量
void PutChar(uint8 Data); //发送一个字节
void Send(uint8 Data); //发送一个数据包
//串行通信协议
//2字节起始位
#define STARTBYTE1 0x23 //'#'
#define STARTBYTE2 0x24 //'$'
bit SerialCanSend = 1; //用来指示当前串口发送部分是否空闲
bit BlankLEDEnable = 0; //用来指示是否闪烁LED
void Command(void);
void Receive(void);
void Temperature(void);
void BlankLED(void);
sbit LED7 = P1^7;
#define BIT0 1
#define BIT1 2
#define BIT2 4
#define BIT3 8
#define BIT4 16
#define BIT5 32
#define BIT6 64
#define BIT7 128
uint8 OS_Q_MEM_SEL KeyValue[16]; //给命令消息队列分配的队列空间
/******************************************************
** LCD LM016L 硬件接口及预定义
P0 LCD BUS
P10 RS
P11 RW
P12 E
******************************************************/
sbit LcdEn = P1^2;
sbit LcdRw = P1^1;
sbit LcdRs = P1^0;
#define DBPort P0
#define LCD_COMMAND 0 // Command
#define LCD_DATA 1 // Data
#define LCD_CLEAR_SCREEN 0x01 // 清屏
#define LCD_HOMING 0x02 // 光标返回原点
//设置显示模式
#define LCD_SHOW 0x04 //显示开
#define LCD_HIDE 0x00 //显示关
#define LCD_CURSOR 0x02 //显示光标
#define LCD_NO_CURSOR 0x00 //无光标
#define LCD_FLASH 0x01 //光标闪动
#define LCD_NO_FLASH 0x00 //光标不闪动
//设置输入模式
#define LCD_AC_UP 0x02
#define LCD_AC_DOWN 0x00 // default
#define LCD_MOVE 0x01 // 画面可平移
#define LCD_NO_MOVE 0x00 //default
//内部等待函数
unsigned char LCD_Wait(void)
{
LcdRs=0;
LcdRw=1; _nop_();
LcdEn=1; _nop_();
LcdEn=0;
return DBPort;
}
//向LCD写入命令或数据
void LCD_Write(bit style, unsigned char input)
{
LcdEn=0;
LcdRs=style;
LcdRw=0; _nop_();
DBPort=input; _nop_();//注意顺序
LcdEn=1; _nop_();//注意顺序
LcdEn=0; _nop_();
LCD_Wait();
}
void LCD_SetDisplay(unsigned char DisplayMode)
{
LCD_Write(LCD_COMMAND, 0x08|DisplayMode);
}
void LCD_SetInput(unsigned char InputMode)
{
LCD_Write(LCD_COMMAND, 0x04|InputMode);
}
void LCD_CLS(void)
{
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
}
//初始化LCD
void LCD_Initial()
{
LcdEn=0;
LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵
LCD_Write(LCD_COMMAND,0x38);
LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动
}
//液晶字符输入的位置************************
void GotoXY(unsigned char x, unsigned char y)
{
if(y==0)
LCD_Write(LCD_COMMAND,0x80|x);
if(y==1)
LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}
//将字符输出到液晶显示
void PrintXY(unsigned char x, unsigned char y,unsigned char *str)
{
OSSemPend(LCDSem,0); //等待其他任务释放LCD
GotoXY(x,y);
while(*str!='\0')
{
LCD_Write(LCD_DATA,*str);
str++;
}
OSSemPost(LCDSem); //释放信号量
}
/********************************************************************************
主程序及任务
*********************************************************************************/
void main(void)
{
OSInit();
//系统节拍中断使用定时器0,中断频率为600Hz,晶振11.0592MHz
TMOD = (TMOD & 0XF0) | 0X01;
TH0 = (65536 - (11059200 / 12) / 600) / 256;
TL0 = (65536 - (11059200 / 12) / 600) % 256;
TR0 = 1;
ET0 = 1;
LCD_Initial();
OSTaskCreate(Receive, NULL, 0);
OSTaskCreate(Command, NULL, 1);
OSTaskCreate(Temperature,NULL,2);
OSTaskCreate(BlankLED,NULL,3);
while(1)
{
PCON = PCON | 0x01; /* CPU进入休眠状态 */
}
}
//主任务
/*********************************************************************************************************
** 函数名称: command
** 功能描述: 命令处理任务
** 输 入: 无
********************************************************************************************************/
void command(void)
{
char DisplayStr[10];
unsigned char cmd;
OSSemCreate(LCDSem,1); //建立信号量,并初始化为1
OSSemCreate(TEMPSem,0); //建立信号量,并初始化为0
while (1)
{
OSQPend(&cmd,CommandData,0);
//串口命令处理放在下面
//以下演示一些简单的功能
switch(cmd)
{
case 'c':
LCD_CLS();
break;
case 'a':
BlankLEDEnable = 1; //LED D7 ON
break;
case 'b':
BlankLEDEnable = 0; //LED D7 off
break;
case 't':
OSSemPost(TEMPSem); //置信号量,启动测温任务
break;
case 'h':
PrintXY(0,0," "); //clear line
PrintXY(0,0,"Hello");
break;
case 'g':
PrintXY(0,0," "); //clear line
PrintXY(0,0,"Good Boy!");
break;
default:
sprintf(DisplayStr, "Recive: %c",cmd);
PrintXY(0,0,DisplayStr);
break;
}
}
}
/*********************************************************************************************************
** 函数名称: SerialInit
** 功能描述: 初始化串行口
********************************************************************************************************/
void SerialInit(void)
{
SCON = 0x50; //8位,允许接受
PCON = 0; //取消双倍波特率控制位
TMOD = TMOD & 0x0F; //设置TIMER 1 为波特率发生器(8位自动载入计时/计数器)
TMOD = TMOD | 0x20;
TH1 = 0xfd; //com is 9600 b/s
TL1 = 0xfd;
TR1 = 1;
ES = 1;
}
/*********************************************************************************************************
** 函数名称: Send
** 功能描述: 发送一个数据包
** 输 入: Data:指向要发送的数据指针
** 输 出: 无
********************************************************************************************************/
void Send(uint8 Data)
{
PutChar(STARTBYTE1);
PutChar(STARTBYTE2);
PutChar(Data);
PutChar(Data);
}
/*********************************************************************************************************
** 函数名称: PutChar
** 功能描述: 发送一个字节
** 输 入: Data:发送的数据
********************************************************************************************************/
void PutChar(uint8 Data)
{
OS_ENTER_CRITICAL(); //由于使用了全局变量SerialCanSend,需要互斥访问,所以这里关中断
if (SerialCanSend == 1)
{
SerialCanSend = 0;
SBUF = Data;
}
else
{
OSQIntPost(SerialOutData,Data);
}
OS_EXIT_CRITICAL(); //开中断
}
/*********************************************************************************************************
** 函数名称: Receive
** 功能描述: 串口接收处理任务
** 输 入: 无
** 输 出: 无
** 全局变量: 无
** 调用模块: 无
********************************************************************************************************/
void Receive(void)
{
uint8 data temp,temp1;
/* 建立所需要的消息队列 */
OSQCreate(CommandData,16);
OSQCreate(SerialInData,16);
OSQCreate(SerialOutData,32);
SerialInit(); /* 初始化串行口 */
printf("Ready");
while (1)
{
OSQPend(&temp,SerialInData,0); /* 接收一个字节 */
while (1)
{
OSQPend(&temp1,SerialInData,0); /* 接收一个字节 */
if ((temp == STARTBYTE1) && (temp1 == STARTBYTE2))
{
break; /* 接收到起始字符 */
}
temp = temp1;
}
OSQPend(&temp1,SerialInData,0);
OSQPend(&temp,SerialInData,0);
if(temp == temp1)
{
OSQPost(CommandData,temp); //接收到完整的数据,发送消息给命令处理任务
Send('0'); //ok
}
else
{
Send('1'); //通信错误
}
}
}
/*********************************************************************************************************
** 函数名称: comm
** 功能描述: 串口中断处理程序
** 输 入: 无
** 输 出: 无
** 全局变量: 无
** 调用模块: 无
********************************************************************************************************/
#pragma disable /* 除非最高优先级中断,否则,必须加上这一句 */
void comm(void) interrupt 4
{
uint8 data temp;
if (RI == 1)
{
OS_INT_ENTER(); //进入中断(中断嵌套处理)
RI = 0;
OSQIntPost(SerialInData,SBUF);
OSIntExit(); //中断出
return;
}
if (TI == 1)
{
TI = 0;
if (OSQAccept(&temp,SerialOutData) == OS_Q_OK) //从发送数据消息队列中取出消息
{
SBUF = temp;
}
else
{
SerialCanSend = 1; //置空闲标志
}
}
}
void BlankLED(void)
{
while(1)
{
while(BlankLEDEnable)
{
LED7 = 0;
OSWait(K_TMO,OS_TICKS_PER_SEC/50);
LED7 = 1;
OSWait(K_TMO,OS_TICKS_PER_SEC/50);
}
LED7 = 1;
}
}
void Temperature(void)
{
float TemperValue;
char DisplayStr[10];
while(1)
{
OSSemPend(TEMPSem,0);
//GetTemperature(); //读温度值,本例没有包含
//演示用温度值
TemperValue = 25.4;
sprintf(DisplayStr,"%4.1f C",TemperValue);
PrintXY(0,1,DisplayStr);
}
}
/********************************************************************************************************
** End Of File
********************************************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -