DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1651|回复: 1
打印 上一主题 下一主题

[待整理] 单片机C51编程几个有用的模块(2)

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-5 14:07:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机C51编程几个有用的模块(2)

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

    建立工程:
    在硬盘上建立文件夹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文件。
//
// File: Config.h
//
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include <Atmel/At89x52.h>                 // 使用AT89C52做控制
#include “../Common/Common.h”                // 使用自定义的数据类型
#define TIMER_RELOAD            922        // 11.0592MHz晶振,1ms中断周期
#define TIMER_KBSCANDELAY    40        // 40ms重检测按键状态,即40ms消抖
#define SCOMM_AsyncInterface                // 使用异步通讯服务
#define IsPackageHeader(x)        ((x) == 0xff)    // 判断包头是不是0xff
#define IsPackageTailer(x, y, z)    ((y) <= (z))    // 判断包的长度是不是足够
#endif // _CONFIG_H_

//
// File: Example.c
//
#include <Atmail/At89x52.h>
#include “../Common/Common.h”
#include “../Common/Timer.h”
#include “../Common/Scomm.h”
#include “../Common/KBScan.h”

BIT gbitLampState = 1;                        // 灯的状态,缺省为off

static void Initialize()
{
    InitTimerModule();                        // 初始化时钟模块
    InitSCommModule(0xfd, TRUE);            // 初始化通讯模块,11.0592MHz晶振,
                                        // 波特率为19200
    EA = 1;                                // 开中断
}

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

// 在中断外部响应时钟中断事件
void OnTimerEvent()                        
{
    // do nothing
}

// 控制外部灯
static void TriggerLamp(BIT bEnable)   
{
    P10 = ~bEnable;                        // 需要反相控制
}

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

// 计算校验和
static BYTE CalcCheckSum(BYTE* pbyBuf, BYTE byLen)
{
    BYTE by, bySum = 0;
    for(by = 0; by < byLen; by++)
        bySum += pbyBuf[by];
    return 0 – bySum;
}

// 接收到键盘消息回调函数
void OnKeyPressed(BYTE byValue, BYTE byState)
{
    BYTE by[4];
    if(byState == 0)
    {
        switch(byValue)
        {
        case 0x01:
            gbitLampState = ~g    bitLampState;    // 灯状态取反
            TriggerLamp(gbitLampState);    // 执行控制
            by[0] = 0xff;                    // 构造数据包
            by[1] = 0x12;
            by[2] = (BYTE)gbitLampState;
            by[3] = CalcCheckSum(by, 3);    // 求校验和
            SendPackage(by, 4);            // 发送数据包
            break;
        // 处理其它扫描码
        default:
            break;
    }
}

// 接收到数据包回调函数
void OnRecePackage(BYTE* pbyBuf, BYTE byBufLen)
{
    BYTE by[4];
    by[0] = 0xff;
    by[1] = 0x11;
    if(byBufLen != 4 || pbyBuf[3] != CalcCheckSum(pbyBuf, 3))
    {
        by[2] = 0;
        by[3] = CalcCheckSum(by, 3);
        SendPackage(by, 4);                 // 处理长度或校验和不正确
    }

    switch(pbyBuf[1])
    {
    case 0x10:
        gbitLampState = (BIT)pbyBuf[2];
        TriggerLamp(gbitLampState);
        by[2] = 1;
        by[3] = CalcCheckSum(by, 3);
        SendPackage(by, 4);                // 发送成功执行通知
        break;

    default:                                // 不知道的命令
        by[2] = 0;
        by[3] = CalcCheckSum(by, 3);
        SendPackage(by, 4);                // 发送没有成功执行通知
        break;
    }
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2024-12-27 15:02 , 耗时 0.080958 秒, 18 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表