蓝桥杯单片机练习_第九届彩灯控制器

一、题目要求

1-硬件框图

2-功能描述

2-1 基本描述

  1. 通过单片机控制 8 个 LED 指示灯按照特定的顺序亮灭。

  2. 指示灯的流转间隔可通过按键调整,亮度可由电位器 RB2 进行控制。
  3. 各工作模式的流转间隔时间需在 E2PROM 中保存,并可在硬件重新上电后,自动载入。

    2-2 设计说明

  4. 关闭蜂鸣器、继电器等与本试题程序设计无关的外设资源。
  5. 设备上电后默认数码管、LED 指示灯均为熄灭状态。
  6. 流转间隔可调整范围为 400ms-1200ms。
  7. 设备固定按照模式 1、模式 2、模式 3、模式 4 的次序循环往复运行。

    2-3 LED 指示灯工作模式

  8. 模式 1:按照 L1、L2…L8 的顺序,从左到右单循环点亮。
  9. 模式 2:按照 L8、L7…L1 的顺序,从右到左单循环点亮。
  10. 模式 3:

  11. 模式4:

2-4 亮度等级控制

检测电位器RB2的输出电压,控制8个LED指示灯的亮度,要求在0V-5V
的可调区间内,实现 4 个均匀分布的 LED 指示灯亮度等级。

2-5 按键功能


二、程序源码

#include "stc15.h"
#include "iic.h"
#include <stdio.h>

#define uchar unsigned char
#define uint unsigned int
    
#define KEYCOM P3                   //按键IO
#define KEY_S7 0x01
#define KEY_S6 0x02
#define KEY_S5 0x04
#define KEY_S4 0x08
#define PWM_MAX 19            //pwm周期 <20

uchar code smg_dis[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};
uchar code LED_Max[]={7,7,3,3};//模式轮转时 数组最大下标
uchar code LED_MODE1[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar code LED_MODE2[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
uchar code LED_MODE3[]={0x81,0x42,0x24,0x18};
uchar code LED_MODE4[]={0x18,0x24,0x42,0x81};
uint code PWM_Val[]={0,5,10,15,20};//亮度调节PWM值

uchar Smg_Buf[8]={10,10,10,10,10,10,10,10};
uchar Led_Time[4]={4,4,4,4};//轮转时间

bit LED_Switch=0;//led轮转开关
bit KEY_Flag=0;
bit ADC_Flag=0;
bit SET_Flag=0;
bit Bilik_Flag=0;//0.8s闪烁

uchar Trg , Cont;//键值
uchar Rank=1;//光照等级

void Delay2ms();//写入延时
void UartInit(void);
void Timer0Init(void)   ;
void KeyRead ();
void KEY_Dispose (void);//按键处理
void Set_Show (uchar mode);
void Write_AT24 (uchar add,uchar dat);
uchar Read_AT24 (uchar add);
uchar Read_ADC (uchar add);//读取adc
uchar KEY_Resize (uchar sum,uchar Max,uchar Min);//按键调整数值

void main ()
{
    uchar ADC_Val;
    P0=0x00;P2=0xa0;P2=0x00;
    P0=0xff,P2=0x80,P2=0x00;
    UartInit();
    Timer0Init();
    Led_Time[0]=Read_AT24(0x01);
    Led_Time[1]=Read_AT24(0x02);
    Led_Time[2]=Read_AT24(0x03);
    Led_Time[3]=Read_AT24(0x04);
    if( Led_Time[0]>=4 && Led_Time[1]>=4 && Led_Time[2]>=4 && Led_Time[3]>=4 );//判断读取到的间隔是否小于预设值 小于则为失败
    else
    {
        Led_Time[0]=4;
        Led_Time[1]=4;
        Led_Time[2]=4;
        Led_Time[3]=4;      
    }
    while(1)
    {
        if(KEY_Flag)
        {
            KEY_Flag=0;
            KEY_Dispose();//处理按键事件
            if(!SET_Flag && (Trg & KEY_S4 || Cont & KEY_S4))//普通状态显示亮度
            {
                Smg_Buf[6]=11;
                Smg_Buf[7]=Rank;
            }
            else if (!SET_Flag)
            {
                Smg_Buf[6]=10;
                Smg_Buf[7]=10;
            }   
        }
        if(ADC_Flag)//亮度判断
        {
            ADC_Flag=0;
            ADC_Val=Read_ADC(0x03);
            if(ADC_Val<=69)
                Rank=1;
                else if (ADC_Val>69&&ADC_Val<=131)
                    Rank=2;
                    else if (ADC_Val>131&&ADC_Val<=193)
                        Rank=3;     
                            else if (ADC_Val>193&&ADC_Val<=255)
                                Rank=4;
        }
    }
}

void Timer0Init(void)       //[email protected]
{
    AUXR |= 0x80;       
    TMOD &= 0xF0;       
    TL0 = 0xCD; 
    TH0 = 0xD4;     
    TF0 = 0;        
    TR0 = 1;        
    ET0 = 1;
    EA  = 1;
}

void TIME0() interrupt 1
{
    static uint LedCount =0;
    static uchar KeyCount =0;
    static uchar SmgCount =0;
    static uchar SmgLen=0;
    static uchar AdcCount=0;
    static uint BilikCount=0;
    static uchar i =0;
    static uchar PWM;
    static uchar  Run_Mode =1;
    
    if(++KeyCount>10)
    {
        KeyCount=0;
        KEY_Flag=1;
    }
    
    if(++AdcCount>100)
    {
        AdcCount=0;
        ADC_Flag=1;
    }

    if(SET_Flag)//设置下闪烁所选位
    {       
        if( ++BilikCount>800)
        {
            BilikCount=0;
          Bilik_Flag=~Bilik_Flag;//不可手动清0
        }
    }
        if(++SmgCount>1)
        {
            SmgCount=0;
            P0=~smg_dis[Smg_Buf[SmgLen]];P2=0xe0;P2=0x00;
            P0=1<<SmgLen;P2=0xc0;P2=0x00;
            if(++SmgLen>7)SmgLen=0;
        }
        /*****************/
            PWM++;
            if(PWM <= PWM_Val[Rank])
            {
                switch(Run_Mode)//模式
                {
                    case 1 :P0=~LED_MODE1[i]; break;
                    case 2 :P0=~LED_MODE2[i]; break;
                    case 3 :P0=~LED_MODE3[i]; break;
                    case 4 :P0=~LED_MODE4[i]; break;
                }
                P2=0x80;P2=0x00;
            }
            else if(PWM < PWM_MAX&&PWM>PWM_Val[Rank])//pwm周期小于20ms 视觉残留
            {
                P0=~0x00;
                P2=0x80;P2=0x00;
            }
            else
            {
                PWM=0;
            }
        /*****************/
    if(!LED_Switch)//暂停时 不影响亮度
    {
        ++LedCount;
        if(LedCount > Led_Time[Run_Mode-1]*100)
        {
            LedCount=0;
            ++i;
            if( i > LED_Max[Run_Mode-1])
            {               
                i=0;
                Run_Mode++;//模式切换
                if(Run_Mode==5)Run_Mode=1;
            }   
        }
    }
}

void KeyRead (void)
{
    uchar ReadData = KEYCOM ^ 0xff;
    Trg = ReadData & (ReadData ^ Cont);
    Cont = ReadData;
}

void KEY_Dispose (void)
{
    static uchar SET_MODE=0,mode1=0;
    KeyRead();
    if( Trg & KEY_S7 )
    {
        LED_Switch=~LED_Switch;
    }
    if( Trg & KEY_S6 )
    {
        if(!SET_Flag)
        {
            SET_MODE=0;
            SET_Flag=1;
            mode1=0;
        }
            else
                SET_MODE++;
                if(SET_MODE>=2)//退出设置 清空显示缓存 便于亮度显示 向EEPROM写入间隔
                {
                    SET_MODE=0;
                    SET_Flag=0;
                    Smg_Buf[0]=10;
                    Smg_Buf[1]=10;
                    Smg_Buf[2]=10;
                    Smg_Buf[3]=10;
                    Smg_Buf[4]=10;
                    Smg_Buf[5]=10;
                    Smg_Buf[6]=10;
                    Smg_Buf[7]=10;
                    Write_AT24(0x01,Led_Time[0]);//写入间隔
                    Delay2ms();//必须延时
                    Write_AT24(0x02,Led_Time[1]);
                    Delay2ms();
                    Write_AT24(0x03,Led_Time[2]);
                    Delay2ms();
                    Write_AT24(0x04,Led_Time[3]);
                    Delay2ms();
                }
    }
    if(SET_Flag)//设置模式
    {
        if(SET_MODE==0)
        {
            mode1=KEY_Resize(mode1,3,0);
            Set_Show(mode1);
            if(Bilik_Flag)//闪烁模式位
            {
                Smg_Buf[1]=10;
            }
        }
        else
        {
            Led_Time[mode1]=KEY_Resize(Led_Time[mode1],12,4);
            Set_Show(mode1);
            if(Bilik_Flag)//闪烁轮转间隔
            {
                Smg_Buf[4]=10;
                Smg_Buf[5]=10;
                Smg_Buf[6]=10;
                Smg_Buf[7]=10;
            }
        }
    }
}

uchar KEY_Resize (uchar sum,uchar Max,uchar Min)
{
    char Temp;//无字符型uchar <0时会超过取值范围
    Temp=sum;
    if(Trg & KEY_S5)
    {
        if( ++Temp > Max ) Temp=Max;
    }
    if(Trg & KEY_S4)
    {
        if( --Temp < Min ) Temp=Min;
    }
    return Temp;
}

void UartInit(void)     //[email protected] 
{
    SCON = 0x50;        
    AUXR |= 0x01;       
    AUXR |= 0x04;       
    T2L = 0xE0;     
    T2H = 0xFE;     
    AUXR |= 0x10;   
    TI=1;
}

void Set_Show (uchar mode)
{
    Smg_Buf[0]=11;
    Smg_Buf[1]=mode+1;
    Smg_Buf[2]=11;
    Smg_Buf[3]=10;
    if(Led_Time[mode]<10)//当轮转时间小于1000时 即<10 不显示千位
        Smg_Buf[4]=10;
        else
            Smg_Buf[4]=Led_Time[mode]/10;//1000位
    Smg_Buf[5]=Led_Time[mode]%10;//100位
    Smg_Buf[6]=0;
    Smg_Buf[7]=0;//个位与十位一直为0
}

uchar Read_ADC (uchar add)//读取adc
{
    uchar Temp;
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    IIC_SendByte(add);
    IIC_WaitAck();
    IIC_Start();
    IIC_SendByte(0x91);
    IIC_WaitAck();
    Temp=IIC_RecByte();
    IIC_WaitAck();
    IIC_Stop();
    return Temp;
}

void Write_AT24 (uchar add,uchar dat)
{
    IIC_Start();
    IIC_SendByte(0xa0);
    IIC_WaitAck();
    IIC_SendByte(add);
    IIC_WaitAck();
    IIC_SendByte(dat);
    IIC_WaitAck();
    IIC_Stop();
}

uchar Read_AT24 (uchar add)
{
    uchar Temp;
    IIC_Start();
    IIC_SendByte(0xa0);
    IIC_WaitAck();
    IIC_SendByte(add);
    IIC_WaitAck();
    IIC_Start();
    IIC_SendByte(0xa1);
    IIC_WaitAck();
    Temp=IIC_RecByte();
    IIC_WaitAck();
    IIC_Stop(); 
    return Temp;
}

void Delay2ms()     //@11.0592MHz
{
    unsigned char i, j;

    _nop_();
    _nop_();
    i = 22;
    j = 128;
    do
    {
        while (--j);
    } while (--i);
}


猜你喜欢

转载自www.cnblogs.com/nsss/p/10536531.html