经过多次写往年省赛题的练习,最终我形成了一套相对通用的模板。
(不包括各个模块)(计划在蓝桥杯之前整理一下各个模块的使用)
头文件
分文件编写便于代码查找添加以及修改
sys.h
#ifndef _SYS_H
#define _SYS_H
#include "STC15F2K60S2.h"
#include "intrins.h"
typedef unsigned char uchar;
typedef unsigned int uint; //便于定义无符号型以及节省内存空间
void sel_138(uchar i);
void sys_init();
#include "seg.h"
#include "key.h"
#include "led.h"
//此处包含各个模块的头文件
#endif
在编写各个模块的c文件时直接包含sys.h即可
如此在各个模块中定义的全局变量只需在该模块的h文件中extern即可,
不需在使用时每次extern
系统初始化
sys.c
#include "sys.h"
//通过138译码器选择锁存器
void sel_138(uchar i)
{
switch(i)
{
case 4:
P2 = (P2 & 0x1F) | 0x80;
break;
case 5:
P2 = (P2 & 0x1F) | 0xA0;
break;
case 6:
P2 = (P2 & 0x1F) | 0xC0;
break;
case 7:
P2 = (P2 & 0x1F) | 0xE0;
break;
default:
P2 = P2 & 0x1F;
break;
}
}
//系统初始化 关闭蜂鸣器及led
void sys_init()
{
sel_138(4);
P0 = 0xff;
sel_138(5);
P0 = 0x00;
sel_138(0);
}
数码管
seg.c
#include "sys.h"
code uchar seg_code[] =
{
0xc0,
0xf9,
0xa4,
0xb0,
0x99,
0x92,
0x82,
0xf8,
0x80,
0x90, //0-9
0xbf, // -
//加小数点则 -128
};
uchar seg_buff[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
//直接改变seg_buff的值即可改变数码管
//例如 seg_buff[6] = seg_code[10];
//单个数码管显示
void seg_show(uchar pos, uchar dat)
{
P0 = 0xff;
sel_138(7);
sel_138(6);
P0 = 0x01 << pos;
sel_138(0);
P0 = 0xff;
sel_138(7);
P0 = dat;
sel_138(0);
}
//数码管刷新,放入中断
void seg_scan()
{
static uchar i=0;
seg_show(i, seg_buff[i]);
i++;
i &= 0x07;
}
//定时器初始化,可直接用isp烧录软件生成
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //开启定时器0中断,此处需自己添加
}
//1ms进入一次中断
void Timer_0() interrupt 1
{
seg_scan();
key_scan(); //按键扫描也放在此处
}
key.c
独立按键
#include "sys.h"
sbit key_in_0 = P3^3;
sbit key_in_1 = P3^2;
sbit key_in_2 = P3^1;
sbit key_in_3 = P3^0;
uchar key_sta[4] = {0,0,0,0};
uchar key_back[4] = {0,0,0,0};
//按键扫描
void key_scan()
{
static uchar key_buff[4] = {0xff,0xff,0xff,0xff};
uchar i;
//放入1ms的中断中,1ms获取一次按键值
key_buff[0] = (key_buff[0] << 1) | key_in_0;
key_buff[1] = (key_buff[1] << 1) | key_in_1;
key_buff[2] = (key_buff[2] << 1) | key_in_2;
key_buff[3] = (key_buff[3] << 1) | key_in_3;
for(i=0; i<4; i++)
{
if(key_buff[i] == 0x00)
{
key_sta[i] = 1;//判断按键按下
}
else if(key_buff[i] == 0xff)
{
key_sta[i] = 0;//判断按键弹起
}
}
}
//按键按下判断哪个按键
void key_get()
{
uchar i;
for(i=0; i<4; i++)
{
if(key_back[i] != key_sta[i])
{
if(key_back[i] == 0) //按下执行,若为1,则是弹起执行
{
//判断i的值,执行相应按键动作
}
}
key_back[i] = key_sta[i];
}
}
//按下显示,松开还原
//放入按键判断key_get中
if(i == )
{
while(key_sta[0] == 1)
{
//显示
}
//还原
}
矩阵按键
#include "sys.h"
sbit key_in_0 = P3^3;
sbit key_in_1 = P3^2;
sbit key_in_2 = P3^1;
sbit key_in_3 = P3^0;
sbit key_out_0 = P4^4;
sbit key_out_1 = P4^2;
sbit key_out_2 = P3^5;
sbit key_out_3 = P3^4;
uchar key_buff[4][4] = { {0xff,0xff,0xff,0xff}, {0xff,0xff,0xff,0xff}, {0xff,0xff,0xff,0xff}, {0xff,0xff,0xff,0xff} };
uchar key_sta[4][4] = { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} };
uchar key_back[4][4] = { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} };
void key_scan()
{
static uchar key_i = 0;
uchar i;
key_buff[key_i][0] = (key_buff[key_i][0] << 1) | key_in_0;
key_buff[key_i][1] = (key_buff[key_i][1] << 1) | key_in_1;
key_buff[key_i][2] = (key_buff[key_i][2] << 1) | key_in_2;
key_buff[key_i][3] = (key_buff[key_i][3] << 1) | key_in_3;
for(i=0; i<4; i++)
{
if(key_buff[key_i][i] == 0x00) //按下
{
key_sta[key_i][i] = 1;
}
else if(key_buff[key_i][i] == 0xff) //弹起
{
key_sta[key_i][i] = 0;
}
}
key_i++;
key_i = key_i & 0x03;
switch(key_i)
{
case 0:
key_out_0 = 0; key_out_1 = 1; key_out_2 = 1; key_out_3 = 1;
break;
case 1:
key_out_0 = 1; key_out_1 = 0; key_out_2 = 1; key_out_3 = 1;
break;
case 2:
key_out_0 = 1; key_out_1 = 1; key_out_2 = 0; key_out_3 = 1;
break;
case 3:
key_out_0 = 1; key_out_1 = 1; key_out_2 = 1; key_out_3 = 0;
break;
default:
break;
}
}
void key_get()
{
uchar i,j,key_code;
for(i=0; i<4; i++)
{
for(j=0; j<4; j++)
{
if(key_back[i][j] != key_sta[i][j])
{
if(key_back[i][j] == 0)
{
key_code = i*4 + j + 1;
seg_buff[6] = seg_code[key_code / 10];
seg_buff[7] = seg_code[key_code % 10];
}
}
key_back[i][j] = key_sta[i][j];
}
}
}
led
led
uchar led_buff = 0xff;
void led_scan()
{
P0 = 0xff;
select_138(4);
P0 = led_buff;
select_138(0);
}
//直接调用函数开关led即可
void led_set(uchar i,bit set_bit) //Ledi 1开 0关
{
if(set_bit) //开
{
led_buff &= ~(0x01<<i);
}
else
{
led_buff |= (0x01<<i);
}
}
led pwm
void led_close()
{
sel_138(0);
P0 = 0xff;
sel_138(4);
sel_138(0);
}
void Timer_1() interrupt 3
{
static uchar i=0;
if(i <= pwm)
{
led_scan();
}
else
{
led_close();
}
i++;
if(i == 5) i = 0;
}
//定时器可根据pwm调节档位数设定中断进入时间
//led肉眼不可见闪烁即可
//这里设置的是200us
void Timer1Init(void)
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x38; //设置定时初值
TH1 = 0xFF; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
}