蓝桥杯单片机学习15——第十二届省赛题

这篇具有很好参考价值的文章主要介绍了蓝桥杯单片机学习15——第十二届省赛题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

书接上文,上期我们基本完成了十三届省赛题,但还是存在一些问题,本期我将对上期存在的一些问题,提出一些解决方案,并加以实践验证可行性,废话少说,让我们往下看。

上一期遗留的问题

上期我们提到,数码管和LED在使用的时候会存在外设之间相互干扰的问题,在我们不断的探索之下,我发现其实不仅仅是LED和数码管,继电器和蜂鸣器之间也会存在相互干扰的问题…………
导致我们在控制其中一个外设时,其他的外设也会被干扰,出现一些奇怪的问题,对于这种干扰,我们老师教了我一种很神奇的方法,下面让我来介绍一些这种方法神奇在哪。

解决的方法

  • 通过创建数组来实现对数码管/LED的控制

什么意思呢?我们知道,我们蓝桥杯单片机是通过74HC573锁存器实现P0口对大量外设的控制的,这样的方法毋庸置疑是节省了大量的IO口,但也由于这样的设定,导致P0口的电平一直处于跳变之中,上一秒控制LED的亮起与熄灭,下一秒就去控制数码管的显示了,导致每一个LED(外设)的状态没有被记录下来,而下一次再来控制LED的时候,此时的P0口电平早已不是之前控制LED的电平状态了,也就是因为这个原因,导致由74HC573锁存器控制的各个外设之间相互干扰,互相打架。

因此我们可以通过创建一个数组,来控制LED/数码管,甚至所有通过锁存器控制的外设。具体实现代码如下:

1. LED

数组LED[8] 记录8个LED的状态,为1亮起,为0熄灭,

unsigned char LED[8] = {0,0,0,0,0,0,0,0};       //LED显示数组
//LED写入函数,写入内容为LED数组的内容,1表示开启LED,反之则为关闭LED
void LED_Control(unsigned char* p )
{
    unsigned char temp = 0;
    unsigned char i = 0;
    for(i=0;i<8;i++)
    {
        if(*(p+i) != 0)
        {
            temp |= 0x01<< i ;
        }
    }
    LS_Set(4);
    P0 = ~temp;
    LS_Set(0);
}

2. 数码管

通过对SEG[8] 写入数据,将SEG_Index[SEG[pos]] 写入P0口,实现对数码管的完美控制

unsigned char SEG[8] = {20,20,20,20,20,20,20,20};   //数码管显示数组
//数码管段码
                                    //0   1                                       9    
unsigned char code SEG_Index[30] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
                                    /*0.  1.                                      9. */
                                    0x40, 0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x10,0x20,
                                    /*消隐   。   -     P    A    C*/
                                    0xFF,0x7F,0xBF,0x8C,0x88,0xC6};
//数码管显示函数,显示内容为SEG_Index【SEG】数组的内容,
void SEG_Control(unsigned char* p)
{
    unsigned char i = 0;
    for(i=0;i<8;i++)
    {
        LS_Set(0);
        LS_Set(6);
        P0 = 0x01<<i;
        LS_Set(0);
        LS_Set(7);
        P0 = SEG_Index[*(p+i)];
        LS_Set(0);
        P0 = 0xFF;		
        DelayXms(1);
        
    }
}
												其他的外设也可以用类似的控制方法实现,后面遇到了我再去实现

这样写的好处

好处是什么呢?那可太多了。

下次我们需要修改数码管/LED的状态时,只需要改变数组中的内容,然后通过定时器每个一段时间(我用的是10ms)刷新一次LED/数码管的状态,就可以实现对LED/数码管的完美控制了。而且还减少了CPU的占用。

你就说好不好吧😎😎

解决了这个问题之后,我们继续回到今天的正题,十二届省赛题实操。

任务要求

1.基本要求

蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言

2.竞赛板配置要求

蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言

3.硬件框图

蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言

4.功能描述

蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言

实现思路

关于实现思路,我做出一个优化,具体结构是这样的:

蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言
我将单片机代码进行了一个区分,分别为数码管显示函数、按键扫描函数、逻辑处理函数、数据处理函数,将不同功能的代码放置到对应的函数,然后每隔一段时间对数码管和按键扫描函数调用,这样看起来更加简介,在便于调试的同时,节省了单片机的资源。

代码实现

1.main.C

#include <STC15F2K60S2.H>
#include "LS138.h"
#include "Key.h"
#include "onewire.h"
#include "iic.h"
    
unsigned char LED[8] = {0,0,0,0,0,0,0,0};       //LED显示数组
unsigned char SEG[8] = {20,20,20,20,20,20,20,20};   //数码管显示数组
unsigned int Tempreature = 2425;                //温度
unsigned int Tempreature_Set = 2500;            //温度参数
unsigned int V_DAC= 325;                        //DAC输出电压
unsigned int Key_Num = 0;                       //键码值

unsigned int Page = 1;                          //显示的页面
unsigned int Mode = 1;                          //模式
unsigned char SEG_Flag = 0;                     //数码管显示标志
unsigned char Tempreature_Flag = 0;             //温度读取标志位

//定时器1初始化,十六位自动重装载,1ms触发一次
void Timer1_Init(void)
{
    TMOD = 0x00;
    ET1 = 1;
    EA = 1;
    TH1 = 0xFC;
    TL1 = 0x18;
    TR1 = 1;
}
//初始化函数
void Init()
{
    LS_Init();      //关闭蜂鸣器和继电器
    Timer1_Init();  //定时器1初始化
    LED_Control(LED);   //关闭所有LED
    SEG_Control(SEG);   //关闭所有数码管
   Tempreature =  DS_Read_Tempreatur();     //读取温度
}

 //温度界面显示函数
void Wendu_Page(unsigned  int Tempreature) 
{
    SEG[0] = 25;
    SEG[1] = 20;
    SEG[2] = 20;
    SEG[3] = 20;
    SEG[4] = Tempreature/1000%10;
    SEG[5] = Tempreature/100%10  +10;
    SEG[6] = Tempreature/10%10;
    SEG[7] = Tempreature%10;
}
//参数设置显示界面
void Canshu_Page(unsigned int Tempreature_Set )
{
    SEG[0] = 23;
    SEG[1] = 20;
    SEG[2] = 20;
    SEG[3] = 20;
    SEG[4] = 20;
    SEG[5] = 20;
    SEG[6] = Tempreature_Set/1000%10;
    SEG[7] = Tempreature_Set/100%10;
}

//DAC输出电压显示界面
void DAC_Page(unsigned int V_DAC)
{
    SEG[0] = 24;
    SEG[1] = 20;
    SEG[2] = 20;
    SEG[3] = 20;
    SEG[4] = 20;
    SEG[5] = V_DAC/100%10 + 10 ;
    SEG[6] = V_DAC/10%10;
    SEG[7] = V_DAC%10;
}

//数码管任务,通过Page来决定显示的界面,
void SEG_Task(void)
{   
    switch(Page)
    {                                           //控制对应的LED亮起
        case 1: Wendu_Page(Tempreature);        LED[1] = 1;LED[2] = 0; LED[3] = 0;
            break;
        case 2: Canshu_Page(Tempreature_Set);   LED[1] = 0;LED[2] = 1; LED[3] = 0;
            break;
        case 3: DAC_Page(V_DAC);                LED[1] = 0;LED[2] = 0; LED[3] = 1;
            break;
        
    }

    if(SEG_Flag)
    {
        SEG_Control(SEG);       //10ms更新一次数码管和LED显示状态
        LED_Control(LED);
        SEG_Flag = 0;
    }
}

//按键扫描函数,有按键按下则返回键码值,否则键码值为0
void Key_Task(void)
{
    unsigned int temp = 0;
    temp = KeyScan();
    if(temp != 0)
    {
        Key_Num = temp;
    }
    
}

//处理逻辑相关的任务
void Logic_Task(void)
{
    unsigned  int temp = 0;
    temp = Tempreature_Set;
    if(Key_Num == 4)        //按键4按下,改变显示界面
    {
        Page++;
        if(Page >= 4)
        {
            Page = 1;
        }
    }
    if(Key_Num == 5)        //按键5按下,改变模式
    {
        Mode++;
        if(Mode >= 3)
        {
            Mode = 1;
        }
    }
    if(Page == 2 && Key_Num == 8)   //参数界面下,按键8按下,参数减一
    {
        temp -= 100;
    }
    if(Page == 2 && Key_Num == 9)   //参数界面下,按键8按下,参数加一
    {
        temp += 100;
    }
    Tempreature_Set = temp;
}

//处理数据相关的任务函数
void Data_Task(void)
{
    if(Tempreature_Flag)    //每100ms测量一次温度
    {
        Tempreature =  DS_Read_Tempreatur();
        Tempreature_Flag = 0;
    }
    if(Mode == 1)       //模式1,DAC输出电压与温度相关
    {
        LED[0] = 1;
        if(Tempreature < Tempreature_Set )
        {
            IIC_DAC(0x00);  //温度小于温度参数,输出0V电压
        }
        else
        {
            IIC_DAC(0xFF);  //温度大于温度参数,暑促5V电压
        }
    }
    if(Mode == 2)       //模式2,DAC输出电压如图7所给关系
    {
        LED[0] = 0;     
        if(Tempreature <= 2000)     //小于20度,输出1V
        {
            IIC_DAC(0x33);
        }
        if(Tempreature >= 4000)     //大于40度,输出4V
        {
            IIC_DAC(0xCC);
        }
        else                        //呈线性关系
        {
             IIC_DAC((1 + (Tempreature /100 - 20)*3/20) *51) ;
        }
    }
}

void main()
{
    Init();     //初始化函数调用
    while(1)
    {
        SEG_Task();         //数码管,LED显示函数
        Key_Task();         //按键扫描函数
        Logic_Task();       //逻辑相关处理
        Data_Task();        //数据相关处理
    }
}

//定时器中断服务函数
void Timer1_Handler() interrupt 3
{
    static unsigned int Timer1_Count = 0;
    Timer1_Count++;
    
if(Timer1_Count % 10 == 0)  //每10ms刷新一次数码管和LED显示状态
{
    SEG_Flag = 1;
}
    if(Timer1_Count % 100 == 0)     //每100ms读取一次温度
    {
        Tempreature_Flag = 1;
    }
    
    
}

2.LS138.h

#ifndef __LS138_H_
#define __LS138_H_

#include <STC15F2K60S2.H>

//延时函数,延时Xms  
void DelayXms(unsigned int x);

//初始化函数
void LS_Init(void);

//LS138位选函数,输入0为清除位选
void LS_Set(unsigned int dat);

//LED写入函数,写入内容为LED数组的内容,1表示开启LED,反之则为关闭LED
void LED_Control(unsigned char* p );

//数码管显示函数,显示内容为SEG_Index【SEG】数组的内容,
void SEG_Control(unsigned char* p);

#endif 

3.LS138.C

#include "LS138.h"

//数码管段码
                                    //0   1                                       9    
unsigned char code SEG_Index[30] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
                                    /*0.  1.                                      9. */
                                    0x40, 0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x10,0x20,
                                    /*消隐   。   -     P    A    C*/
                                    0xFF,0x7F,0xBF,0x8C,0x88,0xC6};
        
//延时函数,延时Xms                                    
void DelayXms(unsigned int x)		//@12.000MHz
{
	unsigned char i, j,k;
    
	for(k=0;k<x;k++)
    {
            i = 12;
        j = 169;
        do
        {
            while (--j);
        } while (--i);
    }
}
//初始化函数
void LS_Init(void)
{
    LS_Set(5);
    P0 = 0x00;  //关闭蜂鸣器和继电器
    LS_Set(0);
}
//LS138位选函数,输入0为清除位选
void LS_Set(unsigned int dat)
{
    switch(dat)
    {
        case 0: P2 = P2 & 0x1F;
            break;
        case 4: P2 = (P2 & 0x1F) | 0x80;
            break;
        case 5: P2 = (P2 & 0x1F) | 0xA0;
            break;
        case 6: P2 = (P2 & 0x1F) | 0xC0;
            break;
        case 7: P2 = (P2 & 0x1F) | 0xE0;
            break;

    }
}
//LED写入函数,写入内容为LED数组的内容,1表示开启LED,反之则为关闭LED
void LED_Control(unsigned char* p )
{
    unsigned char temp = 0;
    unsigned char i = 0;
    for(i=0;i<8;i++)
    {
        if(*(p+i) != 0)
        {
            temp |= 0x01<< i ;
        }
    }
    LS_Set(4);
    P0 = ~temp;
    LS_Set(0);
}

//数码管显示函数,显示内容为SEG_Index【SEG】数组的内容,
void SEG_Control(unsigned char* p)
{
    unsigned char i = 0;
    for(i=0;i<8;i++)
    {
        LS_Set(0);
        LS_Set(6);
        P0 = 0x01<<i;
        LS_Set(0);
        LS_Set(7);
        P0 = SEG_Index[*(p+i)];
        LS_Set(0);
        P0 = 0xFF;
        DelayXms(1);
        
    }
}

4.按键扫描函数

#include "Key.h"

//按键扫描函数,返回值为键码值,键码值为0表示按键按下为送手或无按键按下
unsigned int KeyScan(void)
{
    	static unsigned char    cnt = 0,	//continue value
	                last_trg = 0;	        //last trigger value
	unsigned char   trg = 0,	        //trigger value
            cur = 0,                //current value
            value = 3,             //必须初始化为3
            key_x = 0,
            key_y = 0;

    P3 = 0x0f;
    P4 = 0x00;
    if(!P30)        key_x = 3;          //获取X轴坐标
    else if(!P31)   key_x = 2;
    else if(!P32)   key_x = 1;
    else if(!P33)   key_x = 0;

    P3 = 0xf0;
    P4 = 0xff;
    if(!P34)        key_y = 4;          //获取Y轴坐标
    else if(!P35)   key_y = 3;
    else if(!P42)   key_y = 2;
    else if(!P44)   key_y = 1;

    cur = key_y^0;
    trg = cur^cnt & cur;
    cnt = cur;
    if((last_trg ^ trg & last_trg) && cur)
    {
        //计算矩阵按键的键值
        value = key_x + key_y * 4;
    }
    last_trg = trg;

    return value;    //返回独立按键的键值
    
}

5.温度读取函数

需要注意的是:这里的单总线延时函数,需要加上一个:for(i=0;i<12;i++);
为什么要这样呢?这是因为官方提供的延时函数时12T工作模式下的,而我们使用的单片机工作在1T模式下,因此需要作此改动。

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
		unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}
//DS18B20读取温度函数
unsigned int  DS_Read_Tempreatur(void)
{
    unsigned int tempreature = 0;
    unsigned char HSB,LSB;
    
    init_ds18b20();
    Write_DS18B20(0xCC);
    Write_DS18B20(0x44);
    
    init_ds18b20();
    Write_DS18B20(0xCC);
    Write_DS18B20(0xBE);
    LSB = Read_DS18B20();
    HSB = Read_DS18B20();
    
    tempreature = (HSB << 8 )| LSB ;
    tempreature = tempreature /16 *100;
    tempreature = tempreature + (LSB & 0x0F) * 6.25 ;
    return tempreature;     //返回值放大了100倍,可实现保留两位小数
}

6.DA转换函数

//DA转换函数,转换范围为0~5V
void IIC_DAC(unsigned char dat)
{
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();
    IIC_SendByte(0x40);
    IIC_WaitAck();
    IIC_SendByte(dat);
    IIC_WaitAck();
    IIC_Stop();
}

以上就是赛题用到的所有代码,不包含官方提供的驱动代码,如果那里有问题的话,欢迎评论区留言探讨。👀👀👀

总结

十二届的上省赛题总体上来说难度会比十三届的低,也许是我学会了新的方法的原因,也许时我变强了,哈哈哈哈。不过我觉得我上面提供的思路确实不错,对于还没有自己代码风格的小伙伴可以尝试一下,强烈推荐。🫡🫡🫡
蓝桥杯单片机历届试题,蓝桥杯单片机学习,单片机,蓝桥杯,学习,嵌入式硬件,c语言文章来源地址https://www.toymoban.com/news/detail-824456.html

到了这里,关于蓝桥杯单片机学习15——第十二届省赛题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 蓝桥杯单片机第十三届国赛客观题(深夜学习——单片机)

    1.填空题 (2)不同的地址范围: data:0x00-0xff idata:0x0000-0xffff xdata:0x0000-0xffff pdata:0x00-0xff code:0x0000-0xffff 2.选择题 (3)模电——》多级放大电路 (6)DS18B20 (7)模电——》二极管  (8)单片机      

    2024年02月11日
    浏览(42)
  • 蓝桥杯单片机学习14——第十三届省赛题

    上期我们学习了NE555方波发生器频率测量,讲到我会更新之后省赛的题目,那么,他来了。 首先声明:我还没有参加蓝桥杯单片机比赛,也没有拿过奖,所以我写的代码注定不会那么完美,存在BUG是必然的,我写这个系列的目的纯粹是为了记录我的学习………… 关于功能描述

    2024年02月06日
    浏览(32)
  • 【第十四届蓝桥杯单片机冲刺版】

    明天就是正式比赛啦,今天可以在把各个模块练习一遍,常考的外设相关代码一定要熟练哦。 比赛时拿到资料包了,检查驱动文件,使用到的驱动文件,自己做相应的修改,确保是能够正常使用(驱动修改相关可看之前的文章)。 下面是自己将常考的外设结合一起的练习,

    2023年04月27日
    浏览(31)
  • 蓝桥杯单片机(十二)PCF8591(D/A转换)

    接上一篇 蓝桥杯单片机(十一)PCF8591(A/D转换) 首先看蓝桥杯单片机开发板的原理图 AOUT是模拟输出端,AGND为模拟信号地。 模拟参考电压为Vref两端的电压。 由于Vref接到了VCC(5V),所以模拟输出就是以5V为参考电压。 由于PCF8591是8位数模转换,所以 比如0000 00001就是5/255伏。 由于进

    2023年04月09日
    浏览(28)
  • 蓝桥杯STC15F2K60S2单片机 CCP/PCA/PWM模块的学习与使用

    有道是 “一花独放不是春,万紫千红春满园” 我们不能只满足于 眼前所谓的 “够用、能用” 的少量知识,而不去深入学习探究,进而不慎封锁了自己的见识 和 更多 创新开发上的可能性。 曾经仅满足于学习了蓝桥杯单片机的三个外部晶振 定时器: 定时器0、1、2. 就认为完

    2024年02月08日
    浏览(35)
  • 蓝桥杯第十三届单片机国赛程序

    写在前面: 做完总体来说感觉一年比一年难了(估计是被骂的),虽然十三届用的底层少,但是做起来困难重重。 最难的难点在于定时器安排问题。15F2K60S2系列单片机只有三个定时器,本届题目考到了频率测量、超声波、PWM输出,再加上刷新,每一个都需要一个定时器,比

    2024年02月08日
    浏览(38)
  • 蓝桥杯青少组python:第十二届国赛

    1、设 s=\\\"Hi LanQiao\\\" ,运行一下哪个选项代码可以输出 \\\"LanQiao\\\" 子串() A、 print(S[-7:]) B、 print(s[-6:-1]) C、 print(s[-7:0]) D、 print(s[-7:0]) 2、已知 a=2021.0529 ,运行一下代码选项可以输出 2021.05 () A、 print(\\\"{2f}\\\".format(a)) B、 print(\\\"{:.2f}\\\".format(a)) C、 print(\\\"{2}\\\".format(a)) D、 print(\\\"{.2f}\\\".for

    2024年02月07日
    浏览(27)
  • 蓝桥杯单片机第十四届省赛题目和程序答案

    目录  1、前言  2、题目 3、程序架构     3.1 display.c    3.2 ds1302.c    3.3 iic.c    3.4 onewire.c    3.5 main.c 主函数文件    3.6 环境配置 4. 历年蓝桥杯单片机试题和答案        抽空复习了一下,拿下单片机省赛一等奖,在此分享一下最新的14届省赛程序设计答案          模

    2024年02月06日
    浏览(47)
  • 【期末不挂科-单片机考前速过系列P12】(第十二章:单片机的并行拓展例题)经典例题盘点(带图解析)

    前言 大家好吖,欢迎来到 YY 滴单片机系列 ,热烈欢迎! 本章主要内容面向接触过单片机的老铁 主要内容含: 欢迎订阅 YY 滴C++专栏!更多干货持续更新!以下是传送门! YY的《C++》专栏 YY的《C++11》专栏 YY的《Linux》专栏 YY的《数据结构》专栏 YY的《C语言基础》专栏 YY的《

    2024年01月19日
    浏览(54)
  • 第十二届蓝桥杯国赛试题及解析

    第一题 *选择题严禁使用程序验证设s =HiLanQiao\\\',运行以下哪个选项代码可以输出“LanQiao”子串( A )。 A、print(s[-7:]) B、print(s/-6:-11) C、print(s1-7:01) D、print(s[-7:-1]) 第二题 *选择题严禁使用程序验证已知a=2021.0529,运行以下哪个选项代码可以输出“2021.05” ( B )A、print( .2f1\\\'.format(a

    2024年02月08日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包