51单片机模块
Key模块
按键消抖
Key_Val = Key_Read();//读取键码值
Key_Down = Key_Val & (Key_Val ^ Key_Old);//检测下降沿
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//检测上升沿
Key_Old = Key_Val;//扫描辅助变量
Key_Down为检测按下,Key_Up为检测升起,Key_Old 为长按
模块化
4按键
unsigned char Key_Read()
{
unsigned char temp = 0;
if(P3_4 == 0) temp = 1;
if(P3_5 == 0) temp = 2;
if(P3_6 == 0) temp = 3;
if(P3_7 == 0) temp = 4;
return temp;
}
16按键,4按键类似
unsigned char Key_Read()
{
unsigned char temp = 0;
P3_0 = 0;P3_1 = 1;P3_2 = 1;P3_3 = 1;
if(P3_4 == 0) temp = 1;
if(P3_5 == 0) temp = 2;
if(P3_6 == 0) temp = 3;
if(P3_7 == 0) temp = 4;
P3_0 = 1;P3_1 = 0;P3_2 = 1;P3_3 = 1;
if(P3_4 == 0) temp = 5;
if(P3_5 == 0) temp = 6;
if(P3_6 == 0) temp = 7;
if(P3_7 == 0) temp = 8;
P3_0 = 1;P3_1 = 1;P3_2 = 0;P3_3 = 1;
if(P3_4 == 0) temp = 9;
if(P3_5 == 0) temp = 10;
if(P3_6 == 0) temp = 11;
if(P3_7 == 0) temp = 12;
P3_0 = 1;P3_1 = 1;P3_2 = 1;P3_3 = 0;
if(P3_4 == 0) temp = 13;
if(P3_5 == 0) temp = 14;
if(P3_6 == 0) temp = 15;
if(P3_7 == 0) temp = 16;
return temp;
}
主函数调用
Key_Read(数字)
Seg模块
模块化
#include "Seg.h"
unsigned char Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40,0x77,0x39,0x73};
unsigned char Seg_Wela[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
void Seg_Disp(unsigned char wela,dula,point)
{
P0 = 0x00; //复位
P2_6 = 1;
P2_6 = 0;
P0 = Seg_Wela[wela];
P2_7 = 1;
P2_7 = 0;
if(point)
P0 = Seg_Dula[dula] | 0x80;
else
P0 = Seg_Dula[dula];
P2_6 = 1;
P2_6 = 0;
}
使用时配合中断时针程序,快速扫描6个数码管进行显示
主函数调用
Seg_Disp(wela,dula,point)
保存->切换显示模式–彩灯控制系统
Key模块,Seg模块共同操作
使用switch函数和取反标志位set_flag
在Seg_mode不同时,按键的功能不同,在模式一下,按下保存当前的流转间隔;在模式二下,按下第一次按键6->设置是哪个彩灯运行模式,第二次按下->调整的那个彩灯运行模式的流转时间
case 6:
if(Seg_mode==0)
{
for(i=0;i<4;i++)
led_time_set=led_time_data;//读取当前的流转间隔
Seg_mode=1;
}//第一次按下为0,调整模式编号,然后跳出程序
else if(Seg_mode==1)
{
set_flag^=1;//第二次按下调整流转间隔,第三次异或保存参数退出
if(set_flag==0)
{
for(i=0;i<4;i++)
led_time_data=led_time_set;//将设置的数组赋给显示的数组
Seg_mode=0;
}
}
break;
//按键为加按键
case 5:
if(Seg_mode==1)
{
if(set_flag==0)
{
if(++led_time_set_index==4)
led_time_set_index=0;
}
if(set_flag==1)
{
led_time_set[led_time_set_index]=led_time_set[led_time_set_index]+100;
if(led_time_set[led_time_set_index]>=1300)
led_time_set[led_time_set_index]=400;
}
}
break;
数码管显示数据
数据输入不变型–电压采集模块
float Vain;//实际电压
1
采集输入的数据
Vain=(Seg_Buf[2]*1000+Seg_Buf[3]*100+Seg_Buf[4]*10+Seg_Buf[5]+5)/1000.0;
显示输入的数据
数据显示时判断是否为10v和小数点位置
强制转化Vain为整型
case 1://数据显示界面
seg_point[3+(int)Vain/10]=1;//小数点位置判断
Seg_Buf[0]=12;
Seg_Buf[1]=10;
Seg_Buf[2]=10;
Seg_Buf[3]=(int)Vain/10?1:(unsigned char)Vain%10;//判断是否为10v
Seg_Buf[4]=(int)(Vain*100)/10%10;
Seg_Buf[5]=(int)(Vain*100)%10;
break;
数据显示流转型–时钟系统
变量分为显示数组和设置数组
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Clock_disp[3]={23,59,55};//时钟显示数组
unsigned char Clock_set[3];//时钟设置数组
unsigned char Alarm[3] = {0,0,0};//闹钟数组
unsigned char Alarm_set[3];//闹钟设置数组
进入时钟设置界面时,将当时显示的数据传给时钟设置数组
Clock_set[0]=Clock_disp[0];
在经过调整后,按下确认按键,将设置的数据传给显示数组
Clock_disp[0]=Clock_set[0];
闹钟也同理
按下确认按键,将设置的闹钟数据传给闹钟数组
Alarm[0]=Alarm_set[0];
通过改变设置数组,然后赋值的方式完成时钟和闹钟。
Led模块
模块化
#include <Led.h>
void Led_Disp(unsigned char *uled)
{
unsigned char i;
unsigned char temp = 0x00;
static unsigned char temp_old = 0xff;
for(i=0;i<8;i++)//直接扫描每个led的状态
temp |= (uled << (7-i));
if(temp != temp_old)
{
P1 = ~temp;
temp_old = temp;
}
}
主函数调用
Led_Disp(uled[1])
1
时钟和中断
/* 定时器0中断初始化函数 */
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器0中断打开
EA = 1; //总中断打开
}
/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
if(++Seg_Slow_Down == 10) Seg_Slow_Down = 0;//数码管减速专用
if(++Seg_Pos == 6) Seg_Pos = 0;//数码管显示专用
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_point[Seg_Pos]);
if(++Led_Pos == 8) Led_Pos = 0;//led显示专用
Led_Disp(Led_Pos,uled[Led_Pos]);
->灯的亮度等级
->间隔亮灭
->标志位改变
}
减速系统
可以设置按键动作响应时间,数码管刷新时间
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
if(++Seg_Slow_Down == 10) Seg_Slow_Down = 0;//数码管减速专用 10ms刷新一次
在Seg函数和Key函数使用
void Seg_Proc()
{
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;//数码管减速程序
}
间隔500ms亮灭
定义标志位和计时变量
unsigned int time_500ms=0;
bit blink_flag;
中断处使time_500ms每1ms自增到500,标志位取反一次
if(++time_500ms==500)
{
blink_flag^=1;
time_500ms=0;
}
用三目运算符简化程序,但中断程序中Blink_flag为1时,数码管显示,为0时,数码管不显示
Seg_Buf[0]=Blink_flag?(Alarm_set[0]/10%10):10;
灯的亮度等级
设亮度等级变量led_pwm,led_num
if(++led_num ==10) led_num=0;//led显示专用
if(led_num<led_pwm)//灯亮度等级设置
Led_Disp(Led_Pos,uled[Led_Pos]);
else
Led_Disp(Led_Pos,0);
led_pwm=3;//等级一
led_pwm=6;//等级二
led_pwm=9;//等级三
单独选中某个数码管
设一个数组指针变量,后缀为index
按一次按键4在一定范围切换数码管
unsigned char Set_time_count_index
case 4:
if(Seg_mode==1)
{
if(++Set_time_count_index==3)
Set_time_count_index=0;
}
break;
长按
不区分长短按–>在不同模式按键的功能不同–彩灯控制系统
用Key_Down完成长按操作
if(system_flag==0)//系统处于停止界面时
{
if(Key_Old==4 && Seg_mode==0)//长按且处于运行模式
data_seg_flag=1;
else
data_seg_flag=0;//松开回到初始界面
}
else
data_seg_flag=0;
区分长短按–>在同一模式下按键功能不同–温度采集系统
->中断计时时间判断长短按
if(time_flag==1)
{
if(++count_500ms==600)//自加到五百毫秒以上就可以限制住 防止一直按下自加的时候数值越界
count_500ms=600;
}
Key_Down计时
Key_Up->抬起判断按键完成功能
Key_Old->长按
->按键14为减按键,15为加按键,短按一个一个加减,长按快速加减
if(seg_mode==2)
{
if(Key_Down==14) //如果按下S14
time_flag=1; //计时开始
if(Key_Down==15) //如果按下S15
time_flag=1; //计时开始
}
if(count_500ms<500)//短按
{
if(Key_Up==14)//S14抬起
{
time_flag=count_500ms=0;//标志位清零,计时值清零
if(++tem_set[tem_index]>70)
tem_set[tem_index]=10;
}
}
else//长按
{
if(Key_Old==14)//S14按下
{
if(++tem_set[tem_index]>70)
tem_set[tem_index]=10;
}
if(Key_Up==14)//S14抬起
time_flag=count_500ms=0;//标志位清零,计时值清零
}
流转的过渡–彩灯控制系统
->中断部分设置计时
if(system_flag==1)
sys_tick++;
->在led函数部分设置归零,可以更好控制其流转
if(sys_tick==led_time_data[led_mode])
{
sys_tick=0;//计时复位
........
}
->模式四转换模式一,先让第一个灯亮后跳出再执行led模式一,不然一瞬间执行第一个灯看不见亮
case 0:
if(led==0x7e)
led=0xfe;//如果在led模式四最后,先让第一个灯亮,跳出程序再执行led模式一
else
{
led=_crol_(led,1);
if(led==0x7f) led_mode=1;//跳到模式二
}
break;
按键数据0~9输入–温度采集系统
->在模式一下输入数据
if(seg_mode==0 && Key_Down<=10 && Key_Down>=1 && temperature_input_index<=2)//输入0到9数据
{ //不能少了Key_Down>=1不然不会闪烁
temperature_input[temperature_input_index]=Key_Down-1;
temperature_input_index++;
}
按键小数点输入–温度采集系统
case 11://输入小数点数据
if(seg_mode == 0 && point_flag == 0 && temperature_input[0] != 11 && temperature_input_index!=3)//处于温度采集界面、标志位为0、输入数组第一位有数据,且小数点只能在个位和十位
{
//temperature_input_index只有1和2的时候才能进入,输入完数字后指针加一
Seg_point[2+temperature_input_index] = 1;
point_wela = temperature_input_index;//记录此时指针状态 便于后期数据处理
point_flag = 1;//拉高标志位 保证一次输入周期小数点只能使能一次
}
break;
互斥点亮
ucLed[0]=(seg_mode==0);//模式一led1亮led2灭
ucLed[1]=(seg_mode==1);//模式二led0亮led1灭
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/hsshdhhs/article/details/143866561
|
|