爆肝是什么意思| 老鸨是什么| 家里进蛇有什么预兆| faye是什么意思| 乳夹是什么| 狗头什么意思| 饕餮是什么| 研究生体检都检查什么| 梦见洗车是什么意思| 冲喜是什么意思| 纤维增殖灶是什么意思| 支气管激发试验阴性是什么意思| vampire是什么意思| 黑白猫是什么品种| 奴仆宫是什么意思| 骨髓捐赠对自己有什么影响没有| 滢字五行属什么| 卡西欧手表什么档次| 乱的偏旁是什么| 心脏病吃什么药| 发愿是什么意思| 什么功尽弃| 奶泡是什么| 日加匀念什么| 协警是什么编制| 美女是指什么生肖| 湿疹为什么一热就出来| 肺部检查挂什么科| 巧夺天工什么意思| 向日葵是什么| 打歌是什么意思| 为什么会乳糖不耐受| 手指为什么会脱皮| 胆囊结石不能吃什么| 怀女孩有什么征兆| 卤牛肉放什么调料| 梦见自己鞋子破了是什么意思| 眩晕症是什么原因引起| 白佛言是什么意思| 孕期什么时候补钙| 国粹是什么| 庸人自扰之是什么意思| 登革热吃什么药| 肚子疼应该吃什么药| 什么是冰种翡翠| 便秘应该吃什么| 阑尾炎吃什么水果| 玳瑁是什么| 高手过招下一句是什么| 沐雨栉风是什么生肖| 舌头有麻木感什么原因| gpa什么意思| 公分是什么意思| 一天吃一个苹果有什么好处| 徘徊是什么意思| 膝盖窝疼是什么原因| 内分泌科看什么| 商字五行属什么| 本命年有什么说法| 遗精频繁是什么原因| 苏州机场叫什么| 新是什么意思| 喝咖啡心慌是什么原因| 什么叫肠化| 精神衰弱吃什么药| 电气火灾用什么灭火器| 部首和偏旁有什么区别| 为什么肛门会出血| 心理障碍是什么病| 扁桃体化脓是什么原因引起的| 什么药是消炎药| 1950年是什么年| 中秋吃什么| 属龙跟什么属相最配| 尉姓氏读什么的| 胆管炎是什么原因引起的| 七月一号是什么星座| 伊朗用什么语言| 小孩睡觉流鼻血是什么原因引起的| ed是什么| 航母舰长是什么级别| 老人怕冷是什么原因| 长白眉毛是什么征兆| 龙须菜是什么植物| 3月7号什么星座| 千钧一发是什么生肖| 着床什么意思| 舌头溃疡吃什么药| 多尔衮是什么意思| 清影是什么意思| 杀马特什么意思| 牛的尾巴有什么作用| 梦见白萝卜是什么意思| 免疫性疾病是什么意思| 腹部ct能检查出什么| 什么的柳枝| 肝不好看什么科| 五月10号是什么星座| 尿常规白细胞3个加号什么意思| 92年是什么命| 五月有什么节日| 头发少适合什么发型| 僧侣是什么意思| 薄荷有什么作用| 心慌心闷是什么原因| 水瓶男和什么座最配| 什么病才吃阿昔洛韦片| 不止是什么意思| 黑魔鬼烟为什么是禁烟| 鸦片鱼又叫什么鱼| 什么东西最吸引蛇| 老是做噩梦是什么原因| 落是什么生肖| 心肌病吃什么药| 吃什么瘦肚子脂肪最快| 什么的冬天| 生化是什么意思| 吃孕酮片有什么副作用| 用什么能把牙齿洗白| 人参适合什么人吃| 什么是氮肥| 眼睛肿痛什么原因| 吃什么水果| only是什么品牌| everytime什么意思| 农转非是什么意思| fic是什么意思| 石榴花什么时候开花| 佰草集适合什么年龄| 双氢克尿噻又叫什么| 做梦梦见大蟒蛇什么意思| 膝盖跪着疼是什么原因| 吃饭老是噎着是什么原因| 姻亲是什么意思| 什么的列车| 重金属中毒喝什么解毒| happy halloween是什么意思| 大姨妈发黑是什么原因| 伪骨科是什么| 白芨主治什么病| 前列腺增生是什么原因引起的| 什么鱼嘌呤含量低| 什么药溶血栓最好| 动脉夹层是什么病| 智商是什么意思| 疏肝理气喝什么茶| 当医生需要什么条件| 早上起床吐痰带血是什么原因| 输血前四项检查是什么| 双手合十什么意思| 七月八日是什么日子| 眼角下面长斑是什么原因引起的| 尿液有泡沫什么原因| 十天干代表什么| 一抹多是什么意思| 蒙脱石散不能和什么药一起吃| 幽门螺旋杆菌感染吃什么药| 一什么圆月| 深入交流是什么意思| 车前草的作用是什么| 心脏支架和搭桥有什么区别| 普乐安片治什么病| 714什么星座| 琼字代表什么生肖| 电离辐射是指什么| 鸡柳是什么肉| 睾丸痛是什么原因| 为什么会得霉菌性阴道炎| 早晚体重一样说明什么| 龛是什么意思| 孩子血铅高有什么症状| 六味地黄丸什么牌子好| 夜盲症吃什么| 潜血弱阳性是什么意思| 人的五官指什么| 疮痈是什么意思| 什么是生殖器疱疹| 促排是什么意思| 胆红素尿呈什么颜色| 古代内衣叫什么| rh是什么意思| 吃山竹有什么好处| 鼻梁高的男人说明什么| 手上的线分别代表什么图解| 竹子可以做什么| 吃土豆有什么好处和坏处| 医院为什么不推荐腹膜透析| 火影忍者大结局是什么| 肩袖损伤用什么药| 无机磷偏低有什么影响| 嘴唇发紫发黑是什么原因| 肛门上长了个肉疙瘩是什么原因| 荆芥不能和什么一起吃| 海肠是什么东西| 枸杞和红枣泡水喝有什么好处| 钢琴八级是什么水平| 伤元气是什么意思| 肠胃炎吃什么食物| 身份证最后一位代表什么| 2013年五行属什么| 什么猫最贵| 真身是什么意思| 什么是公因数| 不吃肉对身体有什么影响| 不将就是什么意思| 理疗和按摩有什么区别| 琼脂是什么东西| 替身是什么意思| 脾大是什么意思| 什么叫匝道| 月经推迟是什么原因导致的| 男人为什么离不开情人| 什么飞机| 风湿性心脏病吃什么药| 辣子鸡属于什么菜系| 肝脓肿是什么病严重吗| 91网站是什么| 大长今是什么意思| 乘风破浪的意思是什么| 梦见老虎是什么意思| 蚂蚁喜欢吃什么食物| 包皮红肿瘙痒用什么药| 什么化妆品好| 什么叫五行| 烟火气是什么意思| 头皮痒用什么止痒最好| 低血压对身体有什么影响| 6.12是什么星座| 88年属什么的生肖| 屎壳郎的学名叫什么| 十点半是什么时辰| 做宫颈筛查能查出什么| 垂是什么意思| 补充蛋白质提高免疫力吃什么| 为什么流鼻血| 威士忌是用什么酿造的| 喉咙肿瘤有什么症状| 什么是性高潮| 扁桃体肿大是什么原因引起的| 什么草药能治痔疮| 星期一右眼皮跳是什么预兆| 艾是什么意思| 阿托伐他汀钙片什么时候吃最好| 女人脾虚吃什么最好| 血糖有点高吃什么食物好| 月经提前来是什么原因| 免疫力低吃什么| 姊是什么意思| 视力sca分别代表什么| 云南有什么名酒| 龟头敏感早泄吃什么药| 梦见自己生了个儿子是什么意思| 大便想拉又拉不出来是什么原因| 什么的口水| 提拔是什么意思| 海参是补什么| 女人梦见棺材是什么征兆| 网调是什么意思| 做爱女生是什么感觉| 膀胱在什么位置图片| 做梦牙齿掉了是什么预兆| 榜眼是什么意思| 110斤穿什么码衣服| 胃糜烂要吃什么药| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 嵌入式开发 ? STM32 ? 【原创】蓝桥杯单片机组第十届国赛程序题分享--from恶龙咆哮

共10条 1/1 1 跳转至

【原创】蓝桥杯单片机组第十届国赛程序题分享--from恶龙咆哮

工程师
2025-08-04 16:58:22     打赏
百度 根据规划,新建馆舍包括办公大楼、停车场、领务区、维修保养区、绿地与篮球场等。

今天和大家分享一下2019年第十届蓝桥杯单片机决赛的程序题,我在做这道题的时候属实有被难到,今天就和大家分享一下;先看题目:

4、功能描述

4.1功能概述

1)使用超声波测距单元完成测距功能。

2) 通过DS18B20温度传感器完成温度测量功能。

3)通过 PCF8591 D/A 转换芯片完成模拟电压输出功能。

4)通过AT24C02E2PROM存储器完成参数变动次数记录功能。

5)通过竞赛板上的USB 转串口模块实现串口收发功能。

6) 通过键盘、数码管、LED指示灯等完成人机交互操作。

7) 温度(T)、 距离(S)测量结果刷新时间要求

●温度(T)≤0.5秒。

距离(S)≤1秒。

8)距离(S)测量说明

测量范围要求: 10cm - 50cm。

●声音在空气中的传播速度: 340米/秒。

4.2显示功能

1) 数据界面

一 温度数据显示

温度数据界面如图2所示.显示内容包括提示符C和温度值。温度数据单位为摄氏度C,数据保留小数点后两位有效数字,占用4位数码管。

1.png

距高数据显示

距离数据界面如图3所示,显示内容包括提示符L和距离数据。距离数据单位为cm,可显示距离范围0cm-99cm,占用两位数码管。

2.png

变更次数显示

显示内容包括提示符n和参数变动次数。参数变动次数记录范围为0-65535次,占用5位数码管,数据长度不足5位时,高位数码管熄灭。

3.png

2) 参数界面

●温度参数

显示内容包括提示符P、参数编号l和温度参数,温度参数可调整范围0-99。

4.png

距离参数

显示内容包括提示符只、参数编号2和距离参数,距离参数可调整范围0-99。

5.png

好,所有的显示功能都已经在这里了,那么我们就先把这些显示功能的函数写下来,在写显示函数之前,我们要先把准备工作做好,比如关闭继电器、蜂鸣器等,准备好数码管的段选数组:

typedef unsigned int u16;
typedef unsigned char u8;
 
u8 code smgduan[17]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
            0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴显示0~F的值
 
 
void delayms(u16 i)                                           //延迟函数
{
    u16 aa;
    while(i--)
    {
        for(aa=0;aa<845;aa++);
    }
}
                   
void InitHC138(u8 add)                         //Y4、Y5、Y6、Y7通道选择函数
{
    switch(add)
    {
        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;
    }
}
 
void InitHC573() //关闭蜂鸣器、继电器、LED函数
{
    InitHC138(5);
    P0 = 0X00;
    InitHC138(4);
    P0 = 0XFF;
}
 
void DigDisplay(u8 add,u8 dat) //数码管段选、位选函数
{
    InitHC138(6);
    P0 = 0X01 << add;
    InitHC138(7);
    P0 = dat;
}
void GetDatPro()                           //温度获取
{
    
    distance_get = distance;
    temp_get = Tempget();
    temp_get = temp_get*100;
    
}
 
void wave_rec(void)                      //超声波距离获取
{
    
    u8 num = 10;
    TX = 0;
    TL0 = 0xF4;     //设置定时初值
    TH0 = 0xFF;     //设置定时初值
    TR0 = 1;        //定时器0打开
    while(num--)
    {
        while(!TF0);
        TF0 = 0;
        TX ^= 1;
    }
    TR0 = 0;        //定时器0关闭
    TL0 = 0;        //设置定时初值
    TH0 = 0;        //设置定时初值
    TR0 = 1;        //定时器0打开
    while(RX && !TF0);
    TR0 = 0;
    if(TF0)
    {
        TF0 = 0;
        distance = 99;
    }
    else
    {
        distance = ((TH0 << 8) | TL0) * 0.017;
        if(distance > 99) distance = 99;
    }
}

好,准备工作做好后,就先把显示函数写出来:

u16 distance_get,distance_setup = 35;//定义距离变量和参数
u16 temp_get ,temp_setup = 30;       //定义温度变量和参数
u8 setup_count;                     //设置参数
//===================温度数据显示========================
void DisplayTempGet()
{
    DigDisplay(0,~smgduan[12]);
    delayms(1);
    DigDisplay(4,~smgduan[temp_get/1000]);
    delayms(1);
    DigDisplay(5,~(smgduan[temp_get/100%10] | 0x80));
    delayms(1);
    DigDisplay(6,~smgduan[temp_get/10%10]);
    delayms(1);
    DigDisplay(7,~smgduan[temp_get%10]);
    delayms(1);
}
 
//===================距离数据显示========================
void DisplayDistanceGet()
{
    DigDisplay(0,0xc7);
    delayms(1);
    DigDisplay(6,~smgduan[distance_get/10]);
    delayms(1);
    DigDisplay(7,~smgduan[distance_get%10]);
    delayms(1);
}
 
//===================参数数据变动显示========================
void DisplaySetupCount()
{
    DigDisplay(0,0xc8);
    delayms(1);
    
    DigDisplay(7,~smgduan[setup_count%10]);
    delayms(1);
    
  if(setup_count>9)
    {
        
        DigDisplay(6,~smgduan[setup_count/10%10]);
        delayms(1);
    }
    if(setup_count>99)
    {
        DigDisplay(5,~smgduan[setup_count/100%10]);
        delayms(1);
    }
    if(setup_count>999)
    {
        DigDisplay(4,~smgduan[setup_count/1000%10]);
        delayms(1);
    }
    if(setup_count>9999)
    {
        DigDisplay(3,~smgduan[setup_count/10000]);
        delayms(1);
    }
}
 
//===================温度参数显示========================
void DisplayTempSetup()
{
    DigDisplay(0,0x8c);
    delayms(1);
    DigDisplay(3,~smgduan[1]);
    delayms(1);
    DigDisplay(6,~smgduan[temp_setup/10]);
    delayms(1);
    DigDisplay(7,~smgduan[temp_setup%10]);
    delayms(1);
}
 
//===================距离参数显示========================
void DisplayDistanceSetup()
{
    DigDisplay(0,0x8c);
    delayms(1);
    DigDisplay(3,~smgduan[2]);
    delayms(1);
    DigDisplay(6,~smgduan[distance_setup/10]);
    delayms(1);
    DigDisplay(7,~smgduan[distance_setup%10]);
    delayms(1);
}

接下来,我们来看按键模块:
4.3
按键功能

1) “短按键”功能说明

●S13:定义为“界面”按键,按下SI3按键,切换数据界面和参数界面,按键S13切换模式如下图所示:

6.png

界面切换要求:

1)每次从数据界面进入参数界面,默认当前为温度参数。2)每次从参数界面进入数据界面,默认当前为温度数据。.

●S12:定义为“切换”按键。

在数据界面下,按下S12按键,切换显示温度数据、距离数据和参数变更次数。切换模式如下图所示:

7.png

在参数界面下,按下SI2按键,切换显示温度参数和距离参数,切换模式如下图所示:

8.png

●S16: 定义为“减”按键。

在温度参数界面下,按下S16,温度参数减少2℃.

在距离参数界面下,按下S16,距离参数减少5cm

●S17: 定义为“加”按键。

在温度参数界面下,按下S17,温度参数增加2℃。

2)“长按键” 功能说明

●任何界面状态下,长按S12按键,可重置参数变动次数记录为0次。

任何界面状态下,长按S13按键,可切换DAC输出功能,详见4. 6 DAC输出功能。 切换模式如下图所示:

9.png

3) 其它要求

长按键功能触发时间要求:按键按下时间超过1秒,触发长按键功能,否则为短按键。

按键应做好消抖处理,避免出现一次按键功能多次触发等问题。按键长按、短按对应的功能和效果不可互相影响。

请严格按照以上要求,定义各按键长按、短按功能。

这个按键是阉割版的矩阵按键,比较好处理,功能要求看起来似乎有点复杂,其实,只要我们把他们的逻辑写出来就会一目了然,S13只有一个切换功能,我们就用位定义一个变量,只有0和1两个状态,再设几个变量,每当按键按下,只是变量的值在变,不要再按键处理函数里调用显示函数,这样太乱:

void KeyScan()    
{
    R1 = 0;
    R2 = 1;
    C1 = 1;C2 = 1;
    if(C1 == 0)      //S13
    {
        if(turn_dat_setup == 0) //数据界面
        {
            get_dat++;
        }
        else if(turn_dat_setup == 1)
        {
            setup_dat++;
        }
        DA_flag = 1;
        while(!C1);
        DA_flag = 0;
    }
    
    
    else if(C2 == 0)  //S17
    {
        switch(setup_dat)
        {
            case(1):temp_setup = temp_setup+2;break;
            case(2):distance_setup = distance_setup+5;break;          
        }
        setup_count++;
        while(!C2);
    }
    
    R2 = 0;
    R1 = 1;
    C1 = 1;C2 = 1;
    if(C1 == 0)      //S12
    {
        turn_dat_setup = ~turn_dat_setup;
        
        count_flag = 1;
        while(!C1);
        count_flag = 0;
        EEPROM_write(0x01,setup_count/256);
        delayms(5);
        EEPROM_write(0x02,setup_count%256);
        delayms(5);
    }
    
    
    else if(C2 == 0)  //S16
    {
        switch(setup_dat)
        {
            case(1):temp_setup = temp_setup-2;break;
            case(2):distance_setup = distance_setup-5;break;          
        }
        setup_count++;
        while(!C2);
    }
}
 
void DisplayDat()                           //对于按键控制的参数进行显示
{
    if(turn_dat_setup == 0)
    {
        switch(get_dat)
        {
            case(1):DisplayTempGet();break;
            case(2):DisplayDistanceGet();break;
            case(3):DisplaySetupCount();break;
        }
    }
    else if(turn_dat_setup == 1)
    {
        switch(setup_dat)
        {
            case(1):DisplayTempSetup();break;
            case(2):DisplayDistanceSetup();break;
        }
    }
}
 
void SetupDatPro()                     //数据的边界范围处理
{
    if(get_dat > 3)
    {
        get_dat = 1;
    }
    if(get_dat < 1)
    {
        get_dat = 3;
    }
    
    if(setup_dat > 2)
    {
        setup_dat = 1;
    }
    if(setup_dat < 1)
    {
        setup_dat = 2;
    }
    
    if(temp_setup > 99)
    {
        temp_setup = 0;
    }
    if(temp_setup < 0)
    {
        temp_setup = 99;
    }
    
    if(distance_setup > 99)
    {
        distance_setup = 0;
    }
    if(distance_setup < 0)
    {
        distance_setup = 99;
    }
}
 
void Timer2() interrupt 12             //这个是定时器2,我们后面会讨论到
{
    u16 count_sec_setup,count_sec_AD;   
    if (DA_flag)                       //长按键 DA切换
    {
        count_sec_AD++;
        if(count_sec_AD == 500)
        {
            count_sec_AD = 0;
            DA_turn = ~DA_turn;
 
        }
    }
    if(count_flag == 1)             //长按键清零     
    {
        count_sec_setup++;
        if(count_sec_setup == 500)
        {
            setup_count = 0;
            count_sec_setup = 0;
        }
    }
}

4.4存储功能

1)数据的存储

每当一次参数设置操作完成(从参数界面退出,切换回数据界面),如果参
数发生变化,参数变动次数加1,将参数变动次数保存在E2RPOM存储器,要求可记录范围: 0-65535.

2)数据的重置.

参数变动次数可以通过长按S12重置为0次。
存储功能也已经写在按键扫描函数里了;这个是读取函数:

void GetSetupCount()                           //读取EEPROM的数值
{
    u16 count_h,count_l;
    count_h = EEPROM_read(0x01);
    count_l = EEPROM_read(0x02);
    setup_count = ((count_h * 256) + count_l);
}

4.5串口功能

1)通信模式

波特率: 4800 bps

校验位:无校验

停止位: 1位。

2)数据召测功能

通过串口调试软件下发数据召测指令,设备接收到正确指令后,上报数据或参数。召测指令格式要求如下:

①查询数据指令:"ST\r\n”, 接收到指令后,设备返回距离和温度数据,数据格式要求如下:

以字符串形式输出,以’$’开头, "\r\n”结尾。

距离数据(S)和温度数据(T)以’,’间隔。

-格式: $距离数据,温度数据\r\n,

举例: $20,24. 32\r\n

上报的距离数据为整数,温度数据保留小数点后两位有效数字。

②查询参数指令: ”PARA\r\n”,接收到指令后,设备返回当前的距离参数和温度参数。返回数据格式要求如下:

以字符串形式输出,以‘$’开头,” r\n”结尾。

距离参数(S)和温度参数(T)以’,’间隔。

格式: #距离参数,温度参数\r\n

~举例: #35,30\r\n

如设备接收到错误指令,返回”ERROR\r\n”。

备注:

1) 串口查询参数、数据指令响应时间要求: ≤500ms。

2) 串口逻辑功能错乱,发送乱码、错误数据将被酌情扣分。

3) S12、 S13、 S16、 S17按键扫描过程和串口通讯功能应互不影响。
串口这一模块我一直觉得是最难的一块,因为总是不能够顺畅的打开PC和单片机之间的通信。而这道题的难点在于,超声波已经占据一个定时器资源了,我们还需要一个定时器进行定时工作,这个时候就需要打开第三个定时器了,对于第三个定时器,我们使用的<reg52>的头文件没有包含相关的寄存器,需要我们查阅资料进行配置:

sfr T2H = 0xD6;  //定时器2的高八位寄存器
sfr T2L = 0xD7;  //定时器2的低八位寄存器
sfr AUXR = 0X8E;               
sfr T2MOD = 0XC9;
sfr IE2 = 0XAF;
 
u8 RevBuf[20]; //数据接收缓冲区
 
bit rx_flag;
bit send_enable = 0;     //发送标志位
 
u8 rx_tt;                 //
u8 rx_cnt;
 
void UartInit(void)    //4800bps@12.000MHz
{
 
    SCON = 0x50;       //8位数据,可变波特率
    AUXR |= 0x40;      //定时器1时钟为Fosc,即1T
    AUXR &= 0xFE;      //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;      //设定定时器1为16位自动重装方式
    TL1 = 0x8F;     //设定定时初值
    TH1 = 0xFD;     //设定定时初值
    ET1 = 0;        //禁止定时器1中断
    TR1 = 1;        //启动定时器1
    ES = 1;
}
void Time2Init()    //定时器2打开
{
    EA = 1;
    IE2 = (1<<2);
    AUXR &= 0XFB;
    T2L = 0X30;              //2ms
    T2H = 0XF8;
    AUXR |= 0X10;
}
void SendByte(u8 dat)         //串口发送字节
{
    SBUF = dat;
    while(!TI);
    TI = 0;
}
 
void SendDat(u8 *str)          //串口一位一位的发送需要发送的数据
{
    while(*str != '\0')
    {
        SendByte(*str++);
    }
}
 
void Urat() interrupt 4       //串口接收,接收到的数据暂存缓冲区数组中
{
    if(RI == 1)
    {
        RI = 0;
        rx_flag = 1;                 //表示数据已经接收完毕
        RevBuf[rx_cnt++] = SBUF;     // 放入暂存区
    }
}
 
void UratPro()
{
    if(send_enable)                  //允许向PC发送数据
    {
        send_enable = 0;
        SendDat(RevBuf);
    }
     
}
 
void Timer2() interrupt 12 
{   
    if(rx_flag && ++rx_tt >= 50)           //如果数据接收完毕
    {
        rx_flag = 0;
        rx_tt = 0;
        RevBuf[rx_cnt++] = '\0';
        rx_cnt = 0;
        
        if(strcmp(RevBuf,"ST\r\n") == 0)  //判断电脑发送的信息是否一致,如
        {                                 //果一致,发送距离数据
            send_enable = 1;
            sprintf(RevBuf,"$%d,%d\r\n",distance_get,temp_get%100);
        }
        else if(strcmp(RevBuf,"PARA\r\n") == 0)
        {
            send_enable = 1;
            sprintf(RevBuf,"$%d,%d\r\n",distance_setup,temp_setup);
        }
        else
        {
            send_enable = 1;
            sprintf(RevBuf,"ERROR\r\n");
        }
    }
}

4.6DAC输出功能

1) 在启动状态下,DAC输出电压值Vout取决于测距数据(S), 对应关系如下表所示

10.png

2)在停止状态下,DAC 固定输出0. 4V.
DAC功能看起来比较生疏,但其实将底层驱动完善后只用进行一个简单的判断就可以输出了:

void DAPro()     
{
    if(DA_turn == 1)
    {
        if(distance_get <= distance_setup)
        {
            DA_write(102);
        }
        else if(distance_get > distance_setup)
        {
            DA_write(204);
        }
    }
}

4. 7LED指示灯功能

1) 温度指示灯

当温度数据超过温度参数时,指示灯L1点亮,否则熄灭。

2) 距离指示灯

当距离数据小于距离参数时,指示灯L2点亮,否则熄灭。

3)DAC功能指示灯

启动状态下,指示灯L3点亮,停止状态下,指示灯L3熄灭。
每一次试题的最后都要考到LED和蜂鸣器之类的控制,做到这里的时候一定要静下心,必要的时候在纸上写一个逻辑框图就很清晰了:

void LedPro()
{     
    InitHC138(4);
    P0 = 0XFF;
    if(temp_get > temp_setup )
    {
        L1 = 0;
    }else L1 = 1;
    if(distance_get < temp_setup)
    {
        L2 = 0;
    }else L2 = 1;
    if(DA_turn == 1)
    {
        L3 = 0;
    }else L3 = 1;
    
}

4)本试题未涉及的 LED指示灯应处于熄灭状态,不同功能的指示灯状态切换时应互不影响。

1. 8初始状态说明

请严格按照以下要求设计作品的上电初始状态。

1) DAC处于启动状态。

2) 作品上电后。未经任何操作的状态下,数码管处于数据界面下,显示温度

3) 工作参数在每次上电时重置为默认值。

●温度参数: 30℃

●距离参数: 35cm

最后,我们写一个主函数,把核心的函数全部放进去:

void main()
{      
    InitHC573();
    Timer0Init();
    UartInit();
    GetSetupCount();
    Time2Init();
    InitHC138(4);
    P0 = 0XFF;
    while(1)
    {
        wave_rec();
        DisplayDat();
        KeyScan();
        SetupDatPro();
        GetDatPro();
        UratPro();
        DAPro();
        LedPro();
    }
}

在这里,给大家附上完善过的底层驱动代码以供大家参考:

//=======================================================================//
//==========================温度读取底层驱动============================//
//=====================================================================//
#include "onewire.h"
 
/****************************单总线延时函数****************************/
void Delay_OneWire(unsigned int t)
{
    unsigned char aa;
  while(t--)
    {
        for(aa=0;aa<10;aa++);
    }
}
 
/****************************DS18B20芯片初始化****************************/
bit Init_DS18B20(void)
{
    bit initflag = 0;
    DQ = 1;
    Delay_OneWire(12);
    DQ = 0;
    Delay_OneWire(80); 
    DQ = 1;
    Delay_OneWire(10); 
    initflag = DQ;    
    Delay_OneWire(5);
  
    return initflag;
}
 
 
/*******************通过单总线向DS18B20写一个字节****************/
void Write_DS18B20(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        DQ = 0;
        DQ = dat&0x01;
        Delay_OneWire(5);
        DQ = 1;
        dat >>= 1;
    }
    Delay_OneWire(5);
}
 
 
/****************************从DS18B20读取一个字节***********************/
unsigned char Read_DS18B20(void)
{
    unsigned char i;
    unsigned char dat;
  
    for(i=0;i<8;i++)
    {
        DQ = 0;
        dat >>= 1;
        DQ = 1;
        if(DQ)
        {
            dat |= 0x80;
        }       
        Delay_OneWire(5);
    }
    return dat;
}
 
 
/****************************温度读取处理函数****************************/
unsigned char Tempget()
{
    unsigned char low,high,temp;
     Init_DS18B20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    Delay_OneWire(20);
 
     Init_DS18B20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    
    low=Read_DS18B20();
    high=Read_DS18B20();
 
    temp=high<<4;
    temp|=(low>>4);
 
    return temp;
}
 
//======================================================================//
//==========================EEPROM底层驱动=============================//
//=====================================================================//
#include <REG52.H>
#include "intrins.h"
#include "iic.h"
 
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}    
 
 
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
 
//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */
 
 
void DA_write(uchar dat)
{
   IIC_Start();
   IIC_SendByte(0x90);
   IIC_WaitAck();
   IIC_SendByte(0x43);
   IIC_WaitAck();
   IIC_SendByte(dat);
   IIC_WaitAck();
    IIC_Stop(); 
}
 
uchar  AD_read(uchar add)
{
    uchar temp;
      IIC_Start();
      IIC_SendByte(0x90);
    IIC_WaitAck();
      IIC_SendByte(add);
    IIC_WaitAck();
      IIC_Stop(); 
 
    IIC_Start();
      IIC_SendByte(0x91);
    IIC_WaitAck();
      temp=IIC_RecByte();
      IIC_Stop(); 
    return temp;
 
}   
    
    
uchar  EEPROM_read(uchar add)
{
    uchar temp;
      IIC_Start();
      IIC_SendByte(0xA0);
    IIC_WaitAck();
      IIC_SendByte(add);
    IIC_WaitAck();
      IIC_Stop(); 
 
    IIC_Start();
      IIC_SendByte(0xA1);
    IIC_WaitAck();
      temp=IIC_RecByte();
      IIC_Stop(); 
    return temp;
 
 
}   
    
void  EEPROM_write(uchar add,uchar dat)
{
      IIC_Start();
      IIC_SendByte(0xA0);
    IIC_WaitAck();
      IIC_SendByte(add);
    IIC_WaitAck();
      IIC_SendByte(dat);
      IIC_WaitAck();
      IIC_Stop();    
}   
 
    
    
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    somenop;
    SDA = 0;
    somenop;
    SCL = 0;    
}
 
//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    somenop;
    SDA = 1;
}
 
 
 
//等待应答
bit IIC_WaitAck(void)
{
    SDA = 1;
    somenop;
    SCL = 1;
    somenop;
    if(SDA)    
    {   
        SCL = 0;
        IIC_Stop();
        return 0;
    }
    else  
    { 
        SCL = 0;
        return 1;
    }
}
 
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {   
        if(byt&0x80) 
        {   
            SDA = 1;
        }
        else 
        {
            SDA = 0;
        }
        somenop;
        SCL = 1;
        byt <<= 1;
        somenop;
        SCL = 0;
    }
}
 
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char da;
    unsigned char i;
    
    for(i=0;i<8;i++)
    {   
        SCL = 1;
        somenop;
        da <<= 1;
        if(SDA) 
        da |= 0x01;
        SCL = 0;
        somenop;
    }
    return da;
}
 
//======================================================================//
//==========================DS1302时钟底层驱动=========================//
//=====================================================================//
#include "ds1302.h"
 
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
 
//---DS1302时钟初始化2025-08-04星期六23点59分50秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
unsigned char TIME[7] = {50, 59, 23, 0x07, 0x05, 0x06, 0x16};
 
//从DS1302寄存器读出数据
unsigned char read(unsigned char add)
{
    unsigned char i,temp;
    unsigned char dat1,dat2;
    CE=0;
    SCLK=0;
    CE=1;
    writebyte(add);
    for(i=0;i<8;i++)
    {
        SCLK=0;
        temp>>=1;
        if(IO)
        {
            temp|=0x80;
        }
        SCLK=1;
    }
    
    IO=0;
    
    dat1=temp/16;//0XFF 1111 1111
    dat2=temp%16;
    
    temp=dat1*10+dat2;
    
    return temp;
}
 
//写字节
void writebyte(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        SCLK=0;
        IO=dat&0x01;
        SCLK=1;
        dat>>=1;
    }
}
 
//向DS1302寄存器写入数据
void write(unsigned char add,unsigned char dat)
{
    unsigned char num;
    CE=0;
    SCLK=0;
    CE=1;
    writebyte(add);
    num=(dat/10<<4)|(dat%10);// 55
    writebyte(num);
    CE=0;
}
 
 
void Init_DS1302()
{
    unsigned char i;
    write(0x8e,0x00);
    for(i=0;i<7;i++)
    {
        write(WRITE_RTC_ADDR[i],TIME[i]);
    }
    write(0x8e,0x80);
    
}
void readtime()
{
    unsigned char i;
    write(0x8e,0x00);
    for(i=0;i<7;i++)
    {
        TIME[i]=read(READ_RTC_ADDR[i]);
    }
    write(0x8e,0x80);  
}




专家
2025-08-04 17:12:44     打赏
2楼

感谢分享


专家
2025-08-04 08:29:53     打赏
3楼

好资料,学习了。


专家
2025-08-04 08:41:08     打赏
4楼

学习


助工
2025-08-04 08:53:44     打赏
5楼

感谢分享


助工
2025-08-04 08:53:59     打赏
6楼

感谢分享


专家
2025-08-04 09:03:20     打赏
7楼

谢谢分享,学习


院士
2025-08-04 09:08:30     打赏
8楼

谢谢分享


专家
2025-08-04 14:09:04     打赏
9楼

谢谢分享


菜鸟
2025-08-04 14:41:04     打赏
10楼

感谢分享


共10条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
十里八乡什么意思 胸片能查出什么 什么是包皮手术 附耳是什么 长期手淫会有什么危害
黄花菜不能和什么一起吃 拉肚子后吃什么食物好 脚浮肿吃什么药 1974年属什么生肖 乳房疼挂什么科
日本为什么侵略中国 吃什么能去湿气最好 什么是口播 开心的动物是什么生肖 手脚发烫是什么原因造成的
正常尿液是什么味道 黄金是什么 自尊心是什么意思 酸入肝是什么意思 逐年是什么意思
爱而不得是什么感觉hcv7jop4ns5r.cn 震仰盂什么意思hcv9jop8ns3r.cn 血红蛋白什么意思hcv9jop3ns5r.cn 脸上过敏擦什么药膏hcv9jop5ns0r.cn 胃酸是什么原因造成的hcv9jop7ns1r.cn
喇叭裤配什么上衣fenrenren.com 上环要做什么检查hcv8jop9ns9r.cn 脸上不停的长痘痘是什么原因hcv9jop5ns7r.cn 六味地黄丸适合什么人吃hcv9jop4ns4r.cn 看到刺猬有什么预兆hcv9jop5ns3r.cn
前列腺增大是什么原因jasonfriends.com 擤鼻涕带血是什么原因zhongyiyatai.com 零零年属什么hcv8jop6ns6r.cn 花开两朵各表一枝什么意思hcv9jop3ns9r.cn 探囊取物是什么意思hcv9jop3ns3r.cn
脂蛋白高吃什么药能降下来xinmaowt.com bb霜和cc霜有什么区别hcv7jop6ns4r.cn 吃什么补胶原蛋白hcv8jop7ns7r.cn 荒淫无度是什么意思tiangongnft.com 尿液红细胞高是什么原因hcv9jop7ns2r.cn
百度