芯片型号(STC15F2K60S2)
关闭所有外设
电路逻辑
蜂鸣器:达林顿管IN = ~OUT
P0口全部写0,就是关闭
代码模板Init.c
#include <Init.h> //先引用自身.h文件
/**
* @brief介绍 系统初始化函数,关闭LED和蜂鸣器
* @param参数 无
* @retval返回值 无
*/
void System_Init()
{
P0 = 0xff; //关闭LED
P2 = P2 & 0x1f | 0x80; //把P0数据放入Y4锁存器 &与0001 1111(0x1f) 再|或1000 0000(0x80)只改变前三位
P2 &= 0x1f; //高三位关上
P0 = 0x00; //关闭蜂鸣器
P2 = P2 & 0x1f | 0xa0; //选Y5
P2 &= 0x1f; //高三位关上
}
LED模块
电路逻辑
P25~P27选中Y4 ---使其置0---从而使Y4C置1
---Y4C 置1使数据通过锁存器
M74HC573锁存器:
参考数据手册
模式配置:(配置Y4C)
OE 默认接地
LE置1 数据传输(开门 Y4C = 0)
LE置0 数据锁存(关门 Y4C = 1)
或非门 WR默认接地
74HC138译码器
查看数据手册
功能表
用P25~P27去控制Y0~Y7
8421编码
举例
8 4 2 1
C B A
0 1 1 = 0+2+1=3 //选中Y3
1 1 0 = 4+2+0= 6 //选中Y6
代码模板LED.c
#include <Led.h>
/**
* @brief介绍 点亮LED
* @param参数 addr选择亮哪个灯
enable使能标志位 0--使能/1--不使能
* @retval返回值 无
*/
void Led_Disp(unsigned char addr,enable)
{
static unsigned char temp = 0x00; //定义两个中间变量,局部静态变量:静态局部变量存放在内存的全局数据区。函数结束时,静态局部变量不会消失,每次该函数调用时,也不会为其重新分配空间。它始终驻留在全局数据区,直到程序运行结束。静态局部变量的初始化与全局变量类似.如果不为其显式初始化,则C++自动为其初始化为。虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。
static unsigned char temp_old = 0xff; //两个变量表示对于LED灯设置的新旧状态进行比较
if(enable)
temp |= 0x01 << addr; // 打开第addr个灯(|=或等于 :全0为0,有1就为1)
else
temp &= ~(0x01 << addr); // 关闭第addr个灯(&=与等于 :全1为1,有0就为0)
if(temp != temp_old) //新旧状态不一样,则扫描新状态及改变LED状态
{
P0 = ~temp; //改变状态
P2 = P2 & 0x1f | 0x80; //开锁存
P2 &= 0x1f; //关
temp_old = temp; //刷新旧状态,防止出现电流声(避免多次刷新产生电流声)
}
}
矩阵键盘模块
跳线帽插在23上为独立按键,插在12上为矩阵键盘
注意是P36 P37 还是P42 P44
按键扫描 代码模板
/**
* @brief介绍 按键扫描函数
* @param参数 无
* @retval返回值 返回按键键码
*/
unsigned char Key_Read()
{
unsigned char temp = 0; //局部变量必须初始化
P44 = 0; //选中第一列扫描(s4-s7)
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;
P37 = 1; //选中第二列扫描(s8-s11)
P36 = 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; //选中第三列扫描(s12-s15)
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; //选中第一列扫描(s16-s19)
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;
}
疑问:消抖?
共阳极数码管模块
代码模板Seg.c
//.h文件
void Seg_Disp(unsigned char wela,dula,point);
//.c文件
#include <Seg.h>
/**
* @brief介绍 打开数码管
* @param参数 wela位选 选择哪一个数码管亮
dula段选 选择亮哪个数
point小数点标志位
* @retval返回值 无
*/
unsigned char seg_dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//段选,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; //小数点点亮:0x7f 0111 1111
P2 = P2 & 0x1f | 0xe0;
P2 &= 0x1f;
}
大模板框架
/*头文件声明区域*/
#include <STC15F2K60S2.H> //15单片机寄存器专属头文件
#include <Key.h> //按键底层专属头文件
#include <Seg.h> //数码管底层专属头文件
#include <Init.h> //初始化底层专属头文件
#include <Led.h> //Led专属头文件
/*变量声明区域*/
unsigned char Key_Slow_ Down; //按键专属减速函数
unsigned char Key_Val,Key_Old,Key_Down,Key_Up; //按键扫描专用变量
unsigned int Seg_Slow_Down; //数码管减速专用变量(因为此变量数值一般为500,所以用int型)
unsigned char Seg_Pos; //数码管扫描专用变量
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 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_Old ^ Key_Val); //读取按键下降沿
Key_Up = ~Key_Val & (Key_Old ^ Key_Val); //读取按键上升沿
Key_Old = Key_Val; //辅助扫描变量
}
/*信息处理函数*/
void Seg_Proc()
{
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
}
/*其他显示函数*/
void Led_Proc()
{
}
/*定时器0初始化函数*/
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //自己打开定时器中断
EA = 1; //自己打开总中断
}
/*定时器0中断服务函数*/
void Timer0Server() interrupt 1
{
if(++Key_Slow_Down = 10) Key_Slow_Down = 0; //一般是10,可自定义
if(++Seg_Slow_Down = 500) Seg_Slow_Down = 0; //一般是500,可自定义
if(==Seg_Pos = 8) Seg_Pos = 0; //在0-8之间循环,动态扫描
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]); //调用Seg_Disp()函数,在第几个位选处出现什么样的数字以及有没有点号
Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}
/*Main函数*/
void main()
{
Sys_Init(); //引用系统初始化函数
Timer0Init(); //引用定时器0初始化函数
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}