【蓝桥杯】单片机学习(9)——多.c文件初认识及计算器实例

1、多.C文件的初步认识

随着使用的硬件模块的增多,程序量逐步增大,为了方便代码的编写、维护和移植,通常采用多.C文件的形式。将按键、数码管、Lcd1602液晶、I2C等各个模块分别写一个.C文件,里面包含各自的底层驱动代码,再写出对应的头文件。这样在编写main.C文件时,需要使用哪个模块,只需要添加对应的头文件即可。

extern关键字说明

extern关键字 用于外部变量的声明,而不是定义。我们需要在第一次用到该变量的.c文件中声明并定义该变量,其他的.c文件如果需要再次使用该变量,我们只需要声明即可,告诉系统这个变量是存在的,不需要再重复定义。(否则会报错)

以数码管的真值定义为例,我们只需要在smg.c文件中定义该变量,如下:(假设第一个使用到该变量的是SMG.c文件

unsigned char code LedChar[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 
       0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};  
                    //共阳极数码管从0到F的真值

如果我们在main.c中也需要使用到这个变量,只需要在main.c中做如下声明(和首次声明保持一致,code不能少),而不需要再次定义。

extern unsigned char code LedChar[];

2、实例(CT107D开发板)

通过按键和数码管模块写一个简易整数加法计算器,不考虑连加、连减等连续计算,不考虑小数情况。

main.c代码:

#include"key.h"
#include"smg.h"
#include"system.h"

extern u8 LedBuf[] ;
extern u8 code LedChar[];

void main()
{
    All_Int();
    EA = 1;
    TMOD = 0x01;
    TH0 = 0xFC;
    TL0 = 0x67;
    ET0 = 1;
    TR0 = 1;
    LedBuf[0] = LedChar[0];
    while(1)
    {
        KeyDriver();
    }
}

void InterruptTimer0() interrupt 1
{
    TH0 = 0xFC;
    TL0 = 0x67;
    LedScan();
    KeyScan();
}

system.h代码

#include"system.h"

void All_Int()
{
    P2 = (P2&0x1F)|0x80;//Y4,关闭LED灯
    P0 = 0xFF;
    P2 = (P2&0x1F)|0xa0;//Y6,关闭蜂鸣器,继电器
    P2 = 0x00;
    P2 = (P2&0x1F)|0xe0;//Y7,段选,关闭数码管
    P0 = 0xFF;
}

smg.c代码:

#include"smg.h"

u8 code LedChar[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 
       0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};  
                    //共阳极数码管从0到F的真值

u8 LedBuf[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//数码管显示缓冲区

void LedScan()
{
    static u8 index = 0;
    P2 = (P2&0x1F)|0xe0;//段选
    P0 = 0xff;
    P2 = (P2&0x1F)|0xc0;//位选
    P0 = 0x80>>index;
    P2 = (P2&0x1F)|0xe0;//段选
    P0 = LedBuf[index];
    index++;
    index &= 0x07;//加到7之后自动清0
}

void LedShow(u32 num)
{
    signed char i;
    u8 buf[6];

    for(i=0;i<6;i++)
    {
        buf[i] = num %10;
        num = num / 10;
    }
    for(i=5;i>0;i--)
    {
        if (buf[i]==0)
            LedBuf[i] = 0xFF;
        else
            break;
    }
    for(;i>=0;i--)
    {
        LedBuf[i] = LedChar[buf[i]];
    }
}

key.c代码:

#include"key.h"

u8 code KeyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表
    { '1',  '2',  '3', 0x26 }, //数字键1、数字键2、数字键3、向上键
    { '4',  '5',  '6', 0x25 }, //数字键4、数字键5、数字键6、向左键
    { '7',  '8',  '9', 0x28 }, //数字键7、数字键8、数字键9、向下键
    { '0', 0x1B, 0x0D, 0x27 }  //数字键0、ESC键、  回车键、 向右键
};

u8 KeySta[4][4] = {
    {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
};//保存按键值的当前状态

//按键动作函数
void KeyAction(u8 keycode)
{
    static u32 result = 0;
    static u32 attend;
    if(keycode>='0' & keycode<='9')
    {
        attend = (attend * 10) + (keycode - 0x30);
        LedShow(attend);
    }  
    else if(keycode == 0x26)//加法
    {
        result += attend;
        attend = 0;
        LedShow(result);
    }
    else if(keycode == 0x0D)//回车键执行加法运算,实际效果与加号相同
    {
        result += attend;
        attend = 0;
        LedShow(result);   
    }
    else if(keycode == 0x1B)//Esc键,清零
    {
        attend = 0;
        result = 0;
        LedShow(attend);   
    }
}

//按键驱动函数,检测是否有按键按下
void KeyDriver()
{
   u8 i,j;
   static u8 backup[4][4] = {
    {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
    };    //按键备份,保存前一次的值

    for(i=0; i<4; i++)
    {
        for(j=0; j<4; j++)
            {
                if(backup[i][j] != KeySta[i][j])
                {
                    if(backup[i][j] != 0)
                    {
                        KeyAction(KeyCodeMap[i][j]);
                    }
                    backup[i][j] = KeySta[i][j];
                }
            }
    }

}

//按键扫描函数,在定时中断中调用,一般使用间隔1ms
void KeyScan()
{
    u8 i;
    static keyout = 0;
    static keybuf[4][4] = {
    {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},
    {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF}
    };
    
    keybuf[keyout][0]=(keybuf[keyout][0]<<1) | KeyIn_1;
    keybuf[keyout][1]=(keybuf[keyout][1]<<1) | KeyIn_2;
    keybuf[keyout][2]=(keybuf[keyout][2]<<1) | KeyIn_3;
    keybuf[keyout][3]=(keybuf[keyout][3]<<1) | KeyIn_4;  
    
    for(i=0;i<4;i++)
    {
        if((keybuf[keyout][i] & 0x0F) == 0x00)
        {
            KeySta[keyout][i] = 0;
        }
        else if((keybuf[keyout][i] & 0x0F) == 0x0F)
        {
            KeySta[keyout][i] = 1;
        }
    } 
    keyout++;
    keyout &= 0x03;

    switch(keyout)
    {
        case 0:KeyOut_4 = 1;KeyOut_1 = 0;break;
        case 1:KeyOut_1 = 1;KeyOut_2 = 0;break;
        case 2:KeyOut_2 = 1;KeyOut_3 = 0;break;
        case 3:KeyOut_3 = 1;KeyOut_4 = 0;break;
        default :break;
    }
}

system.h代码:

#ifndef __SYSTEM_H
#define __SYSTEM_H

#include"reg52.h"
#include"intrins.h"

typedef unsigned char u8;
typedef unsigned int u16;

//void All_Init();

#endif

smg.h代码:

#ifndef __SMG_H
#define __SMG_H

#include"system.h"

void LedScan();
void LedShow(u32 num);

#endif

key.h代码:

#ifndef __KEY_H
#define __KEY_H

#include"system.h"

sfr P4 = 0xC0;

sbit KeyOut_1 = P3^0;
sbit KeyOut_2 = P3^1;
sbit KeyOut_3 = P3^2;
sbit KeyOut_4 = P3^3;

sbit KeyIn_1 = P4^4;
sbit KeyIn_2 = P4^2;
sbit KeyIn_3 = P3^5;
sbit KeyIn_4 = P3^4;

void KeyDriver();
void KeyScan();
void KeyAction(u8 keycode);
extern void LedShow(u32 num);

#endif

补充: Keil 5模块化编程详细步骤

前一篇: 单片机学习(8)——1602液晶

下一篇: 单片机学习(10)——I2C通信协议与E2PROM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值