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

一、初始化外设

  1. 新建工程:

(1)主函数:

#ifndef MAIN_H
#define MAIN_H

#include "Public.h"

#endif
#include "main.h"


void main()
{
    All_Close();
}

(2)公共函数:

#ifndef PUBLIC_H
#define PUBLIC_H

#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned char    
    

void All_Close();

#endif
#include "Public.h"

/*
选择锁存器,发送信息
*/
void Select(u8 cs,u8 s_data)
{
    P0 = s_data;
    P2 = P2 & 0x1f | (cs<<5);
    P2 &= 0x1f;
}

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

(1)主函数:

#include "main.h"

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

void Timer0_Isr(void) interrupt 1
{
    if(++seg_delay == 300)seg_delay = 0;
    
    SEG_Show(COD[PSI],PSI);
    if(++PSI == 8)PSI = 0;
}


void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    sprintf(COT,"P  %2u %2u",(u16)30,(u16)20);    
//    sprintf(COT,"C     %2u",(u16)24);
    SEG_TSL(COT,COD);
}

(2)数码管:

#ifndef SEG_H
#define SEG_H

#include "Public.h"

void SEG_TSL(u8 *input,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;
    for(i=0;i<8;i++)
    {
        switch(input[i])
        {
            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 'C':output[i] = Seg_Table[12];break;
            case 'P':output[i] = ~0x73;break;
            default:output[i] = 0xff;
        }
    }
}

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

(3)定时器:

#ifndef SIMPLE_H
#define SIMPLE_H

#include "Public.h"

void Timer0_Init(void);
#endif
#include "Simple.h"

void Timer0_Init(void)        //1毫秒@12MHz
{
    AUXR |= 0x80;            //定时器时钟1T模式
    TMOD &= 0xF0;            //设置定时器模式
    TL0 = 0x20;                //设置定时初始值
    TH0 = 0xD1;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    ET0 = 1;                //使能定时器0中断
    EA = 1;
}
  1. 独立按键:

(1)部分主函数:

#include "main.h"

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

void Timer0_Isr(void) interrupt 1
{
    if(++seg_delay == 300)seg_delay = 0;
    if(++key_dealy == 10)key_dealy = 0;
    
    SEG_Show(COD[PSI],PSI);
    if(++PSI == 8)PSI = 0;
}

void Key_Proc()
{
    static u8 key_old;
    u8 key_now=0,key_down=0;
    if(key_dealy)return;
    key_dealy = 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,COD);
    }
}

(2)按键检测函数:

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

(1)部分主函数:

void Timer0_Isr(void) interrupt 1
{
    if(++seg_delay == 300)seg_delay = 0;
    if(++key_dealy == 10)key_dealy = 0;
    
    SEG_Show(COD[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_dealy)return;
    key_dealy = 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显示函数:

/*
    输入8位数据点亮LED灯,1为亮
*/
void LED_Show(u8 l_data)
{
    Select(4,~l_data);
}
  1. PCF8591:

(1)部分主函数:

void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    //改变输出电压
    PCF8591_DAC(3);
    
    
    sprintf(COT,"P  %2u %2u",(u16)30,(u16)20);    
//    sprintf(COT,"C     %2u",(u16)24);
    SEG_TSL(COT,COD);

}

(2)PCF8591:

/*
    DAC输出电压
*/
void PCF8591_DAC(u8 volt)
{
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    
    IIC_SendByte(0x43);
    IIC_WaitAck();
    
    IIC_SendByte(volt*255/5);
    IIC_WaitAck();
    
    IIC_Stop();
}
  1. DS18B20:

(1)部分主函数:

void main()
{
    All_Close();
    Timer0_Init();
    while(1)
    {
        SEG_Proc();
        DS18B20_Proc();
        Key_Proc();
    }
}
void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    //改变输出电压
    PCF8591_DAC(3);
    
//    sprintf(COT,"P  %2u %2u",(u16)30,(u16)20);    
    sprintf(COT,"C     %2u",(u16)ds_data);
    SEG_TSL(COT,COD);

}

void DS18B20_Proc()
{
    if(ds_delay)return;
    ds_delay = 1;    
    
    ds_data = DS18B20_Read()>>4;
}

(2)DS18B20:


/*
    利用DS18B20检测温度
*/
u16 DS18B20_Read()
{
    u8 LSB,MSB;
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    LSB = Read_DS18B20();
    MSB = Read_DS18B20();
    
    return (MSB<<8) | LSB;
}

二、实现功能:

  1. 基本框架:

数码管显示有两种模式:数据显示模式,参数设置模式

参数设置模式又分为上限设置模式和下限设置模式

(1)部分主函数:

void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    //改变输出电压
    PCF8591_DAC(3);
    
    if(seg_mode)
        sprintf(COT,"P  %2u %2u",(u16)temper[1],(u16)temper[0]);
    else
        sprintf(COT,"C     %2u",(u16)ds_data);        

    SEG_TSL(COT,COD);

}

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(seg_mode)
    {
        switch(key_down)
        {
            case 4:seg_mode ^= 1;break;
            case 5:set_mode ^= 1;break;
            case 6:
                temper[set_mode]++;
                if(temper[set_mode]>=100) temper[set_mode] = 0;//防止数据越界
            break;
            case 7:
                temper[set_mode]--;
                if(temper[set_mode]>100) temper[set_mode] = 99;
            break;
        }
    }
    else 
        if(key_down == 4)
        {
      seg_mode ^= 1;
            set_mode = 0;
        }
}
  1. 参考代码:

(1)主函数:

#ifndef MAIN_H
#define MAIN_H

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

//模式定义
u8 seg_mode;// 0为显示模式,1为设置模式
u8 set_mode;// 0为下限,1为上限
//设置模式
u8 temper[2];//0为下限,1为上限
u8 temp[2];
u8 error;
//定时器
u8 key_delay;
u16 seg_delay,ds_delay;
u16 count_ms;
//数码管
u8 COT[9],COD[8],PSI;
//LED
u8 l_data;
//DS18B20
u16 ds_data;
#endif
#include "main.h"

void SEG_Proc();
void Key_Proc();
void DS18B20_Proc();
void Init();
void main()
{
    All_Close();
    Timer0_Init();
    Init();
    while(1)
    {
        SEG_Proc();
        DS18B20_Proc();
        Key_Proc();
    }
}

void Timer0_Isr(void) interrupt 1
{
    if(++seg_delay == 300)seg_delay = 0;
    if(++key_delay == 10)key_delay = 0;
    if(++ds_delay == 500)ds_delay = 0;
    
    SEG_Show(COD[PSI],PSI);
    if(++PSI == 8)PSI = 0;
    
    LED_Show(l_data);
}


void SEG_Proc()
{
    if(seg_delay)return;
    seg_delay = 1;
    
    //改变输出电压
    if(ds_data < temper[0])
        PCF8591_DAC(2);
    else if(ds_data < temper[1])
        PCF8591_DAC(3);
    else 
        PCF8591_DAC(4);
    
    
    if(seg_mode)
        sprintf(COT,"P  %2u %2u",(u16)temp[1],(u16)temp[0]);
    else
        sprintf(COT,"C     %2u",(u16)ds_data);        

    SEG_TSL(COT,COD);

}

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(seg_mode)
    {
        switch(key_down)
        {
            case 4:
                seg_mode ^= 1;
              if(temp[0]<temp[1])
              {
                    temper[0] = temp[0];
                    temper[1] = temp[1];    
                    error = 0;
              }
                else
                    error = 1;
            break;
            case 5:set_mode ^= 1;break;
            case 6:
                temp[set_mode]++;
                if(temp[set_mode]>=100) temp[set_mode] = 0;//防止数据越界
            break;
            case 7:
                temp[set_mode]--;
                if(temp[set_mode]>100) temp[set_mode] = 99;
            break;
        }
    }
    else 
        if(key_down == 4)
        {
      seg_mode ^= 1;
            set_mode = 0;
            temp[0] = temper[0];
            temp[1] = temper[1];    
        }
}

void DS18B20_Proc()
{
    if(ds_delay)return;
    ds_delay = 1;    
    
    ds_data = DS18B20_Read()>>4;
    
    //指示灯
    if(error)
        l_data = 0x01<<3;
    else if(ds_data < temper[0])
        l_data = 0x01<<2;
    else if(ds_data < temper[1])
        l_data = 0x01<<1;
    else 
        l_data = 0x01;
}

void Init()
{
    temper[0] = 20;
    temper[1] = 30;
    
    seg_mode = 0;
}

(2)公共函数:

#ifndef PUBLIC_H
#define PUBLIC_H

#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int    
    

void All_Close();
void Select(u8 cs,u8 s_data);
#endif
#include "Public.h"

/*
选择锁存器,发送信息
*/
void Select(u8 cs,u8 s_data)
{
    P0 = s_data;
    P2 = P2 & 0x1f | (cs<<5);
    P2 &= 0x1f;
}

/*
    关闭无关设备
*/
void All_Close()
{
    //关闭蜂鸣器和继电器
    Select(5,0x00);
    //关闭LED
    Select(4,0xff);
    //清空数码管位选
    Select(7,0xff);
}

(3)数码管:

#ifndef SEG_H
#define SEG_H

#include "Public.h"

void SEG_TSL(u8 *input,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;
    for(i=0;i<8;i++)
    {
        switch(input[i])
        {
            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 'C':output[i] = Seg_Table[12];break;
            case 'P':output[i] = ~0x73;break;
            default:output[i] = 0xff;
        }
    }
}

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

(4)其他外设:

#ifndef SIMPLE_H
#define SIMPLE_H

#include "Public.h"
#include "iic.h"
#include "onewire.h"
void Timer0_Init(void);
u8 D_Key();
void LED_Show(u8 l_data);
void PCF8591_DAC(u8 volt);
u16 DS18B20_Read();
#endif
#include "Simple.h"

void Timer0_Init(void)        //1毫秒@12MHz
{
    AUXR |= 0x80;            //定时器时钟1T模式
    TMOD &= 0xF0;            //设置定时器模式
    TL0 = 0x20;                //设置定时初始值
    TH0 = 0xD1;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    ET0 = 1;                //使能定时器0中断
    EA = 1;
}

/*
    独立按键按键检测
*/
u8 D_Key()
{
    u8 i=0;
    for(;i<4;i++)
        if((P3 & (0x08>>i)) == 0)
            return i+4;
    return 0;
}

/*
    输入8位数据点亮LED灯,1为亮
*/
void LED_Show(u8 l_data)
{
    Select(4,~l_data);
}

/*
    DAC输出电压
*/
void PCF8591_DAC(u8 volt)
{
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    
    IIC_SendByte(0x43);
    IIC_WaitAck();
    
    IIC_SendByte(volt*255/5);
    IIC_WaitAck();
    
    IIC_Stop();
}

/*
    利用DS18B20检测温度
*/
u16 DS18B20_Read()
{
    u8 LSB,MSB;
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    
    init_ds18b20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    LSB = Read_DS18B20();
    MSB = Read_DS18B20();
    
    return (MSB<<8) | LSB;
}
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值