和之前一样建好工程文件夹,里边包含User(放工程文件,mian.c)、Driver(存放底层文件如Led.c,Led.h等)
新建的工程先搭建框架,可以先书写底层函数(此次书写了四个函数并包含相应的头文件共八个底层文件)
比如先用3个IO口控制74HC138译码器,控制Y4为低电平;当Y4为低电平时,或非门74HC02控制Y4C为高电平,使74HC573的OE端口有效,OE端口有效时,可使用P0口控制LED的亮灭。
可以去多了解74HC138译码器,74HC02或非门,74HC573八路输出透明锁存器的相关内容会更好理解
#include <Init.h>
//关闭外设
void System_Init()
{
?? ?P0 = 0xff;
?? ?P2 = P2 & 0x1f | 0x80;
?? ?P2 &= 0x1f;
?? ?P0 = 0x00;
?? ?P2 = P2 & 0x1f | 0xa0;
?? ?P2 &= 0x1f;
}
#include <STC15F2K60S2.H>
void System_Init();
与初始化底层驱动专用文件同理,需要了解对应的锁存器控制,可以在使用的芯片数据手册查看
#include <Led.h>
void Led_Disp(unsigned char addr,enable)
{
?? ?static unsigned char temp = 0x00;
?? ?static unsigned char temp_old = 0xff;
?? ?if(enable)
?? ??? ?temp |= 0x01 << addr;
?? ?else
?? ??? ?temp &= ~(0x01 << addr);
?? ?if(temp != temp_old)
?? ?{
?? ??? ?P0 = ~temp;
?? ??? ?P2 = P2 & 0x1f |0x80;
?? ??? ?P2 &= 0x1f;
?? ??? ?temp_old = temp;
?? ?}
}
#include <STC15F2K60S2.H>
void Led_Disp(unsigned char addr,enable);
(板子上的按键从按键4开始到按键19,可根据实际硬件修改)
#include <Key.h>
unsigned char Key_Read()
{
?? ?unsigned char temp = 0;
?? ?P44 = 0; P42 = 1; P35 = 1; P34 = 1;
?? ?if(P33 == 0) temp = 4;
?? ?if(P32 == 0) temp = 5;
?? ?if(P31 == 0) temp = 6;
?? ?if(P30 == 0) temp = 7;
?? ?P44 = 1; P42 = 0; P35 = 1; P34 = 1;
?? ?if(P33 == 0) temp = 8;
?? ?if(P32 == 0) temp = 9;
?? ?if(P31 == 0) temp = 10;
?? ?if(P30 == 0) temp = 11;
?? ?P44 = 1; P42 = 1; P35 = 0; P34 = 1;
?? ?if(P33 == 0) temp = 12;
?? ?if(P32 == 0) temp = 13;
?? ?if(P31 == 0) temp = 14;
?? ?if(P30 == 0) temp = 15;
?? ?P44 = 1; P42 = 1; P35 = 1; P34 = 0;
?? ?if(P33 == 0) temp = 16;
?? ?if(P32 == 0) temp = 17;
?? ?if(P31 == 0) temp = 18;
?? ?if(P30 == 0) temp = 19;
?? ?return temp;
}
#include <STC15F2K60S2.H>
unsigned char Key_Read();
(这个板子使用的为共阳数码管,若使用的为共阴数码管要更换对应的段码表和位选表;与初始化底层驱动专用文件同理,需要了解对应的锁存器控制,可以在使用的芯片数据手册查看)
#include <Seg.h>
unsigned char Seg_Dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//数码管段码储存数组
unsigned char Seg_Wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//数码管位码储存数组
void Seg_Disp(unsigned char wela,dula,point)
{
?? ?P0 = 0xff; //
?? ?P2 = P2 & 0x1f |0xe0;
?? ?P2 &= 0x1f;
?? ?P0 = Seg_Wela[wela];
?? ?P2 = P2 & 0x1f |0xc0;
?? ?P2 &= 0x1f;
?? ?P0 = Seg_Dula[dula];
?? ?if(point)
?? ??? ?P0 &= 0x7f;
?? ?P2 = P2 & 0x1f |0xe0;
?? ?P2 &= 0x1f;
}
#include <STC15F2K60S2.H>
void Seg_Disp(unsigned char wela,dula,point);
#include <STC15F2K60S2.H>//单片机寄存器专用头文件
#include <Init.h>//初始化底层驱动专用头文件
#include <Led.h>//Led底层驱动专用文件
#include <Key.h>//按键底层驱动专用文件
#include <Seg.h>//数码管底层驱动专用文件
unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键扫描专用变量
unsigned char Key_Slow_Down;//按键减速专用变量 10ms
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned char Seg_Slow_Down;//数码管减速专用变量 500ms
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//Led显示数据存放数组
void Key_Proc()
{
?? ??? ?if(Key_Slow_Down)return;
?? ??? ?Key_Slow_Down = 1;//按键减速程序
?? ??? ?
?? ??? ?Key_Val = Key_Read();//读取按下的键码值
?? ??? ?Key_Down = Key_Val & (Key_Val ^ Key_Old);//捕捉下降沿
?? ??? ?Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//捕捉上升沿
?? ??? ?Key_Old = Key_Val;//辅助扫描
}
void Seg_Proc()
{
?? ??? ?//unsigned char i;//用于for循环
?? ??? ?if(Seg_Slow_Down)return;
?? ??? ?Seg_Slow_Down = 1;//数码管减速程序
}
void Led_Proc()
{
?? ?
}
(这个可以使用STC的定时器计算那里生成c代码,后面要自己添加ET0,EA打开中断)
void Timer0Init(void)?? ??? ?//1毫秒@12.000MHz
{
?? ?TMOD &= 0xF0;?? ??? ?//设置定时器模式
?? ?TL0 = 0x18;?? ??? ?//设置定时初值
?? ?TH0 = 0xFC;?? ??? ?//设置定时初值
?? ?TF0 = 0;?? ??? ?//清除TF0标志
?? ?TR0 = 1;?? ??? ?//定时器0开始计时
?? ?
?? ?ET0 = 1;
?? ?EA = 1;
}
(为了定时执行特定的任务,如此处设置了定时的时间触发了数码管和LED产生特定反应)
void Timer0Server() interrupt 1
{
?? ?
?? ??? ?if(++Key_Slow_Down == 10)Key_Slow_Down =0;
?? ??? ?if(++Seg_Slow_Down == 500)Seg_Slow_Down =0;
?? ??? ?if(++Seg_Pos == 6)Seg_Pos = 0;
?? ??? ?Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
?? ??? ?Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}
void main()
{
?? ?System_Init();
?? ?Timer0Init();
?? ?while(1)
?? ?{
?? ??? ?Key_Proc();
//?? ??? ?Seg_Proc();
?? ??? ?Led_Proc();
?? ??? ?
?? ?}
}
?