访问手机版页面
你的位置:老古开发网 > 51单片机 > 51单片机Keil C51编程 > 正文  
单片机C51编程几个有用的模块(2)
内容导读:
应用举例
现在来举例说明上述几个模块的使用方法。
硬件环境描述:
为了控制一盏灯,需要单片机提供一个做控制功能的开关量,这里不描述外部接口电路,只说明当单片机的P10脚为高电平时,灯灭,当P10脚为低电平时,灯亮。
可以通过计算机由串口发送命令来控制,或通过一个按键(push&nbspbutton不是自锁式的按键)来手动控制(按键接在P11脚上,当键没有按下时,P11电平为高,键按下时,引脚电平被接低),当使用按键手动控制的时候,需要给计算机发送通知。
设定串口通讯指令如下:
数据包由0xff做包头,4个字节长,第二个字节为命令代码,第三个字节为数据,最后一个字节为校验位。
命令和数据代码有如下组合:
(计算机发给单片机)
0x10&nbsp0x01: 计算机控制灯亮。(数据位是非零值即可)
0x10&nbsp0x00: 计算机控制灯灭。
(单片机发给计算机)
0x11&nbsp0x01:单片机正常执行控制指令,返回。(数据位是非零值即可)
0x11&nbsp0x00: 单片机不能够正常执行控制指令,或控制指令错(不明含义的数据包或校验错等)。
0x12&nbsp0x01:手动控制灯亮。(数据位是非零值即可)
0x12&nbsp0x00: 手动控制灯灭。

建立工程:
在硬盘上建立文件夹Projects,在Projects下建立Common文件夹及Example文件夹。将各模块的头文件及实现文件拷贝到Common 文件夹下(推荐使用这样的文件组织结构,其它工程也可以建立在Projects下,各工程共享Common文件夹中的代码)。
启动KeilC的IDE,在Example下建立新工程,将各模块的实现文件包含进工程。
在Example文件夹下建立Output文件夹,更改工程设置,将Output作为输出文件和List文件的输出文件夹(推荐使用这样的结构,当保存工程文件时,可以简单的删除Output文件夹中的内容而不会误删有用的工程文件)。
建立工程配置头文件Config.h及工程主文件Example.c,并将Exmaple.c文件加入工程。

输入代码:
代码的具体编写过程略。下面是最后的Config.h文件及Example.c文件。
//
//&nbspFile:&nbspConfig.h
//
#ifndef&nbsp_CONFIG_H_
#define&nbsp_CONFIG_H_
#include <Atmel/At89x52.h> // 使用AT89C52做控制
#include “../Common/Common.h” // 使用自定义的数据类型
#define&nbspTIMER_RELOAD&nbsp922 //&nbsp11.0592MHz晶振,1ms中断周期
#define&nbspTIMER_KBSCANDELAY&nbsp40 //&nbsp40ms重检测按键状态,即40ms消抖
#define&nbspSCOMM_AsyncInterface // 使用异步通讯服务
#define&nbspIsPackageHeader(x) ((x) ==&nbsp0xff) // 判断包头是不是0xff
#define&nbspIsPackageTailer(x,&nbspy,&nbspz) ((y) <= (z)) // 判断包的长度是不是足够
#endif //&nbsp_CONFIG_H_

//
//&nbspFile:&nbspExample.c
//
#include <Atmail/At89x52.h>
#include “../Common/Common.h”
#include “../Common/Timer.h”
#include “../Common/Scomm.h”
#include “../Common/KBScan.h”

BIT&nbspgbitLampState =&nbsp1; // 灯的状态,缺省为off

static&nbspvoid&nbspInitialize()
{
InitTimerModule(); // 初始化时钟模块
InitSCommModule(0xfd,&nbspTRUE); // 初始化通讯模块,11.0592MHz晶振,
// 波特率为19200
EA =&nbsp1; // 开中断
}

void&nbspmain()
{
Initialize(); // 初始化
while(TRUE) // 主循环
{
ImpTimerService(); // 实现时钟中断服务,如键盘扫描
AsyncRecePackage(4); // 接收4个字节长的数据包
}
}

// 在中断外部响应时钟中断事件
void&nbspOnTimerEvent() 
{
//&nbspdo&nbspnothing
}

// 控制外部灯
static&nbspvoid&nbspTriggerLamp(BIT&nbspbEnable) 
{
P10 = ~bEnable; // 需要反相控制
}

// 键扫描回调函数
BYTE&nbspKBScan() 
{
BIT&nbspb;
P11 =&nbsp1; // 读之前拉高引脚电平
b =&nbspP11; // 读入引脚状态
return ~b; // 数据反相做扫描码
}

// 计算校验和
static&nbspBYTE&nbspCalcCheckSum(BYTE*&nbsppbyBuf,&nbspBYTE&nbspbyLen)
{
BYTE&nbspby,&nbspbySum =&nbsp0;
for(by =&nbsp0;&nbspby <&nbspbyLen;&nbspby++)
bySum +=&nbsppbyBuf[by];
return&nbsp0 –&nbspbySum;
}

// 接收到键盘消息回调函数
void&nbspOnKeyPressed(BYTE&nbspbyvalue,&nbspBYTE&nbspbyState)
{
BYTE&nbspby[4];
if(byState ==&nbsp0)
{
switch(byvalue)
{
case&nbsp0x01:
gbitLampState = ~g&nbspbitLampState; // 灯状态取反
TriggerLamp(gbitLampState); // 执行控制
by[0] =&nbsp0xff; // 构造数据包
by[1] =&nbsp0x12;
by[2] = (BYTE)gbitLampState;
by[3] =&nbspCalcCheckSum(by,&nbsp3); // 求校验和
SendPackage(by,&nbsp4); // 发送数据包
break;
// 处理其它扫描码
default:
break;
}
}

// 接收到数据包回调函数
void&nbspOnRecePackage(BYTE*&nbsppbyBuf,&nbspBYTE&nbspbyBufLen)
{
BYTE&nbspby[4];
by[0] =&nbsp0xff;
by[1] =&nbsp0x11;
if(byBufLen !=&nbsp4  &nbsppbyBuf[3] !=&nbspCalcCheckSum(pbyBuf,&nbsp3))
{
by[2] =&nbsp0;
by[3] =&nbspCalcCheckSum(by,&nbsp3);
SendPackage(by,&nbsp4); // 处理长度或校验和不正确
}

switch(pbyBuf[1])
{
case&nbsp0x10:
gbitLampState = (BIT)pbyBuf[2];
TriggerLamp(gbitLampState);
by[2] =&nbsp1;
by[3] =&nbspCalcCheckSum(by,&nbsp3);
SendPackage(by,&nbsp4); // 发送成功执行通知
break;

default: // 不知道的命令
by[2] =&nbsp0;
by[3] =&nbspCalcCheckSum(by,&nbsp3);
SendPackage(by,&nbsp4); // 发送没有成功执行通知
break;
}

标签:
来源: 作者: 时间:2006/9/25 16:50:53
相关阅读
推荐阅读
阅读排行
最近更新
商品推荐