打印
[经验分享]

51单片机基本模块

[复制链接]
1085|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-25 07:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2028

主题

15904

帖子

14

粉丝