蓝桥杯单片机第十届省赛编程题(深夜学习——单片机)

一、初始化外设:

数码管(定时器)、计数器、独立按键、PCF8591、LED

  1. 新建工程

(1)主函数:

#ifndef MAIN_H
#define MAIN_H

#include "Public.h"



#endif
#include "main.h"
void SEG_Proc();
void main()
{
    All_Close();
    Timer1_Init();
    while(1)
    {
        SEG_Proc();
    }
}


void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
//    sprintf(COT,"F %6u",(u16)6000);
    sprintf(COT,"U    %1.2f",3.41);
    SEG_TSL(COT,C0D);
}

void Timer1_Isr(void) interrupt 3
{
    if(++seg_delay == 500)seg_delay = 0;
    
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
}

(2)公共函数:

#ifndef PUBLIC_H
#define PUBLIC_H


#include <STC15F2K60S2.H>

#define u8 unsigned char 
#define u16 unsigned int 

void Elect(u8 cs,u8 e_data);
void All_Close();

#endif
#include "Public.h"

/*
    选择锁存器,传输数据
*/
void Elect(u8 cs,u8 e_data)
{
    P0 = e_data;
    P2 = P2 & 0x1f | (cs<<5);
    P2 &= 0x1f;
}

/*
    关闭无关设备
*/
void All_Close()
{
    //关闭蜂鸣器和继电器
    Elect(5,0x00);
    //关闭LED
    Elect(4,0xff);
    //关闭数码管
    Elect(7,0xff);
}
  1. 数码管:

(1)主函数:

#ifndef MAIN_H
#define MAIN_H

#include "Public.h"
#include "SIMP_DVI.h"
#include "SEG.h"
#include "stdio.h"

//数码管
u16 seg_delay;
u8 COT[10],C0D[8],PSI;

#endif
#include "main.h"
void SEG_Proc();
void main()
{
    All_Close();
    Timer1_Init();
    while(1)
    {
        SEG_Proc();
    }
}


void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
//    sprintf(COT,"F %6u",(u16)6000);
    sprintf(COT,"U    %1.2f",3.41);
    SEG_TSL(COT,C0D);
}

void Timer1_Isr(void) interrupt 3
{
    if(++seg_delay == 500)seg_delay = 0;
    
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
}

(2)数码管:

#ifndef SEG_H
#define SEG_H


#include "Public.h"

void SEG_TSL(u8 *imput,u8 *output);
void SEG_Show(u8 COD,u8 PSI);
    
#endif
#include "SEG.h"

code unsigned char Seg_Table[] = 
{
    0xc0, //0
    0xf9, //1
    0xa4, //2
    0xb0, //3
    0x99, //4
    0x92, //5
    0x82, //6
    0xf8, //7
    0x80, //8
    0x90, //9
    0x88, //A
    0x83, //b
    0xc6, //C
    0xa1, //d
    0x86, //E
    0x8e //F
};


/*
    输入字符串,输出数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
    u8 i=0,j=0;
    for(i=0;i<8;i++,j++)
    {
        switch(input[j])
        {
            case '0': output[i] = Seg_Table[0];break;
            case '1': output[i] = Seg_Table[1];break;
            case '2': output[i] = Seg_Table[2];break;
            case '3': output[i] = Seg_Table[3];break;
            case '4': output[i] = Seg_Table[4];break;
            case '5': output[i] = Seg_Table[5];break;
            case '6': output[i] = Seg_Table[6];break;
            case '7': output[i] = Seg_Table[7];break;
            case '8': output[i] = Seg_Table[8];break;
            case '9': output[i] = Seg_Table[9];break;
            case 'F': output[i] = Seg_Table[15];break;
            case 'U': output[i] = ~0x3e;break;//~00111110
            default:output[i] = 0xff;
        }
        if(input[j+1] == '.')
        {
            output[i] &= ~0x80;
            j++;
        }
    }
}

/*
    数码管显示函数
*/
void SEG_Show(u8 COD,u8 PSI)
{
    //消隐
    Elect(7,0xff);
    //位选
    Elect(6,0x01<<PSI);
    //段选
    Elect(7,COD);
}

(3)定时器

#ifndef SIMP_DVI_H
#define SIMP_DVI_H


#include "Public.h"

void Timer1_Init(void);    

#endif
#include "SIMP_DVI.h"

/*
    定时器1
*/
void Timer1_Init(void)        //1毫秒@12.000MHz
{
    AUXR |= 0x40;            //定时器时钟1T模式
    TMOD &= 0x0F;            //设置定时器模式
    TL1 = 0x20;                //设置定时初始值
    TH1 = 0xD1;                //设置定时初始值
    TF1 = 0;                //清除TF1标志
    TR1 = 1;                //定时器1开始计时
    ET1 = 1;                //使能定时器1中断
    EA = 1;
}
  1. 独立按键:

(1)部分主函数:

void main()
{
    All_Close();
    Timer1_Init();
    while(1)
    {
        Key_Proc();
//        SEG_Proc();
    }
}

void Timer1_Isr(void) interrupt 3
{
    if(++seg_delay == 500)seg_delay = 0;
    if(++key_delay == 10) key_delay = 0;
    
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
}
void Key_Proc()
{
    static u8 key_old;
    u8 key_now=0,key_down=0;
    if(key_delay)return;
    key_delay = 1;
    
    key_now = D_Key();
    key_down = key_now & (key_now ^ key_old);
    key_old = key_now;
    
    if(key_down)
    {
        sprintf(COT,"%u",(u16)key_down);
        SEG_TSL(COT,C0D);
    }
}

(2)按键检测函数:

#ifndef SIMP_DVI_H
#define SIMP_DVI_H


#include "Public.h"

void Timer1_Init(void);    
u8 D_Key();
#endif
/*
    独立按键按键检测
*/
u8 D_Key()
{
    u8 i=0;
    for(i=0;i<4;i++)
        if((P3 & (0x08>>i)) == 0)
            return i+4;
    return 0;
}
  1. LED:

(1)部分主函数:

void Timer1_Isr(void) interrupt 3
{
    if(++seg_delay == 500)seg_delay = 0;
    if(++key_delay == 10) key_delay = 0;
    
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
    
    LED_Show(l_data);
}

void Key_Proc()
{
    static u8 key_old;
    u8 key_now=0,key_down=0;
    if(key_delay)return;
    key_delay = 1;
    
    key_now = D_Key();
    key_down = key_now & (key_now ^ key_old);
    key_old = key_now;
    
    if(key_down)
    {
        l_data = 0x01<<(key_down-4);
    }
}

(2)LED显示函数:

#ifndef SIMP_DVI_H
#define SIMP_DVI_H

#include "Public.h"

void Timer1_Init(void);    
u8 D_Key();
void LED_Show(u8 l_data);
#endif      
/*
    根据输入的数据显示LED,1为亮灯
*/
void LED_Show(u8 l_data)
{
    Elect(4,~l_data);
}
  1. 计数器:

(1)部分主函数:

void main()
{
    All_Close();
    Timer1_Init();
    Timer0_Init();
    while(1)
    {
//    Key_Proc();
        SEG_Proc();
    }
}

void Timer1_Isr(void) interrupt 3
{
    count_ms++;
    if(++seg_delay == 500)seg_delay = 0;
    if(++key_delay == 10) key_delay = 0;
    
    if(count_ms == 1000)
    {
        freq_num = (TH0<<8) | TL0;                                                                                                                                                                                                                                                                                   
        count_ms = 0;
        TH0 = 0;
        TL0 = 0;
    }
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
    
    LED_Show(l_data);
}

void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    sprintf(COT,"F %6u",freq_num);
//    sprintf(COT,"U    %1.2f",3.41);
    SEG_TSL(COT,C0D);
}

(2)计数器初始化

/*
    初始化计数器0
*/
void Timer0_Init(void)        //100微秒@12MHz
{
    AUXR |= 0x80;            //定时器时钟1T模式
    //计数器模式1
    TMOD |=  0x05;
    TL0 = 0x00;                //设置定时初始值
    TH0 = 0x00;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
}
  1. PCF8591:

(1)部分主函数:

void Timer1_Isr(void) interrupt 3
{
    count_ms++;
    if(++seg_delay == 500)seg_delay = 0;
    if(++key_delay == 10) key_delay = 0;
    
    if(count_ms == 1000)
    {
        freq_num = (TH0<<8) | TL0;                                                                                                                                                                                                                                                                                   
        count_ms = 0;
        TH0 = 0;
        TL0 = 0;
    }
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
    
    LED_Show(l_data);
}

void SEG_Proc()
{
    float show_data=0;
    if(seg_delay)return;
    seg_delay = 1;
    
    show_data = PCF8591_ADC_AIN3();
    PCF8591_DAC(show_data);
//    sprintf(COT,"F %6u",freq_num);
    sprintf(COT,"U    %1.2f",show_data/255*5);
    SEG_TSL(COT,C0D);
}

(2)PCF8591函数:

#ifndef PCF8591_H
#define PCF8591_H


#include "Public.h"
#include "iic.h"

u8 PCF8591_ADC_AIN3();
void PCF8591_DAC(u8 dac_data);
#endif
#include "PCF8591.h"

u8 PCF8591_ADC_AIN3()
{
    u8 dac_data;
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    
    //通道3
    IIC_SendByte(0x43);
    IIC_WaitAck();
    
    IIC_Start();
    IIC_SendByte(0x91);
    IIC_WaitAck();
    
    dac_data = IIC_RecByte();
    IIC_SendAck(1);
    
    IIC_Stop();
    return dac_data;
}

void PCF8591_DAC(u8 dac_data)
{
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    
    //通道3
    IIC_SendByte(0x43);
    IIC_WaitAck();
    
    IIC_SendByte(dac_data);
    IIC_WaitAck();
    
    IIC_Stop();
}

二、实现功能:

  1. 基本功能框架:

数码管可分为三种模式:电压测量模式,频率测量模式,禁用模式。其中电压测量模式分为RB2模式和2V模式

LED并没特别的要求,不用划分模式,在每次操作后改变一下LED灯就行

  1. 参考代码:

(1)主函数:

#include "main.h"
void SEG_Proc();
void Key_Proc();
void Init();
void main()
{
    All_Close();
    Timer1_Init();
    Timer0_Init();
  Init();
    while(1)
    {
        Key_Proc();
        SEG_Proc();
    }
}

void Timer1_Isr(void) interrupt 3
{
    count_ms++;
    if(++seg_delay == 500)seg_delay = 0;
    if(++key_delay == 10) key_delay = 0;
    
    if(count_ms == 1000)
    {
        freq_num = (TH0<<8) | TL0;                                                                                                                                                                                                                                                                                   
        count_ms = 0;
        TH0 = 0;
        TL0 = 0;
    }
    SEG_Show(C0D[PSI],PSI);
    if(++PSI == 8)PSI = 0;
    
    //L3
    if(voli<1.5)
        l_data &= ~0x04;
    else if(voli<2.5)
        l_data |= 0x04;
    else if(voli<3.5)
        l_data &= ~0x04;
    else 
        l_data |= 0x04;
        
    //L4
    if(freq_num<1000)
        l_data &= ~0x08;
    else if(freq_num<5000)
        l_data |= 0x08;
    else if(freq_num<10000)
        l_data &= ~0x08;
    else 
        l_data |= 0x08;
  if(led_turn)        
        LED_Show(l_data);
    else
        LED_Show(0x00);
}

void SEG_Proc()
{
    float show_data=0;
    if(seg_delay)return;
    seg_delay = 1;
    
    //电压检测 电压输出
    show_data = PCF8591_ADC_AIN3();
    voli = show_data/255*5;
    if(voli_sub_mode)
        PCF8591_DAC(show_data);
    else
        PCF8591_DAC(2*255/5);
        
    //不同模式下的显示
    if(seg_turn)
    {
        if(seg_mode)
            sprintf(COT,"F %6u",freq_num);
        else
            sprintf(COT,"U    %1.2f",voli);
    }
    else
        sprintf(COT,"       ");
    SEG_TSL(COT,C0D);
}


void Key_Proc()
{
    static u8 key_old;
    u8 key_now=0,key_down=0;
    if(key_delay)return;
    key_delay = 1;
    
    key_now = D_Key();
    key_down = key_now & (key_now ^ key_old);
    key_old = key_now;
    
    switch(key_down)
    {
        case 4:    
            seg_mode ^= 1;
            l_data = l_data & (~0x03) | (0x01<<seg_mode);
            break;
        case 5:
            voli_sub_mode ^= 1;
            l_data ^= 0x10;
            break;
        case 6:led_turn ^= 1;break;
        case 7:seg_turn ^= 1;break;
    }
}

void Init()
{
    seg_mode = 0;
    l_data = l_data & (~0x03) | (0x01<<seg_mode);
    
    seg_turn = 1;
    led_turn = 1;
    
    voli_sub_mode = 0;
    l_data &= ~0x10;
}

收获:

  1. 能加括号尽量加括号,自主定义优先级

  1. 计数器只能用模式1(未知问题)

3、只有两种状态切换的时候,定义一个变量取反就行

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值