蓝桥杯单片机组小模板 led 数码管 独立按键 矩阵按键

经过多次写往年省赛题的练习,最终我形成了一套相对通用的模板。
(不包括各个模块)(计划在蓝桥杯之前整理一下各个模块的使用)

头文件

分文件编写便于代码查找添加以及修改

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;
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值