搬家网站建设思路,交换友情链接平台,动漫是怎么制作的,网站备案查询app下载目录 前言
单片机资源数据包_2023#xff08;点击下载#xff09;
一、第十一届比赛原题
1.比赛题目
2.赛题解读
1#xff09;计数功能
2#xff09;连续按下无效按键
二、部分功能实现
1.计数功能的实现
2.连续按下无效按键的处理
3.其他处理
1#xff09;对于…目录 前言
单片机资源数据包_2023点击下载
一、第十一届比赛原题
1.比赛题目
2.赛题解读
1计数功能
2连续按下无效按键
二、部分功能实现
1.计数功能的实现
2.连续按下无效按键的处理
3.其他处理
1对于小数的处理
2对于高位为0时熄灭的处理
3对于连续5sV小于Vp的处理
三、完整代码
main.c
iic.c
iic.h 前言
虽然第十一届省赛题目跟十四届相比也很简单但是里面确实也需要许多特殊的处理这里也跟大家分享一下我对里面的一些特殊处理的方式。
老规矩先放资源链接
单片机资源数据包_2023点击下载
一、第十一届比赛原题
1.比赛题目 2.赛题解读
平平常常的四个菜单简简单单按键功能只是对参数的加减这次题目难就难在计数和LED显示部分。所以如果能把按键和数码管写好按键功能实现感觉冲个省二都没问题了。这里只针对上边两个部分进行介绍
1计数功能
计数界面 计数规则 从图上可以看出它想表达的计数时机其实就是当VAIN3电压值从高于Vp也就是电压参数或者说电压预支到低于电压阈值之后计数就1当然从低于阈值到高于阈值这个过程计数不会增加这个VAIN3就是PCF8591的第三个通道。对应到板子上的话就是读取到的电位计的电压。其实这个跟第十四届从亮到暗或者从暗到亮有异曲同工之妙相当于第十四届是这个的升级版。我把第十四届的链接放在下边感兴趣的可以去瞅瞅。至于这个计数怎么实现下边会介绍。
蓝桥杯第十四届电子类单片机组程序设计_蓝桥杯单片机哪一届最难-CSDN博客
2连续按下无效按键
题目上的要求如下
指示灯 L3 连续 3 次以上含 3 次 的无效按键操作触发 L3 点亮直到出现有效的按键操作 L3 熄灭。 之前的题目要求只说某某按键的功能只在某某菜单才可以生效之类的当然这个题目也有这样要求如果在当前菜单按下某个按键后不会响应或者说当前按下的按键没有在它指定的菜单时那就应该记为一次“无效按键操作”。
除此之外呢我个人感觉比如一些本身就没有功能题目没有用到的按键按下之后也应该被标记为“无效的按键操作”因为题目上也没写使用哪些按键完成操作。
同样的具体的实现下边会提到。
二、部分功能实现
1.计数功能的实现
要想精确计数我们肯定得实时读取电压值V这个肯定是不可避免的了。我们知道PCF8591读取到的都是数字量取值0到255我们需要先把它转化为模拟量加上题目要求的Vp以及需要显示的电压值要精确到小数点后两位这里在转换时就直接把V的值扩大100倍方便计算和处理。 unsigned char ad0;//读取到的AD值 unsigned int V0;//当前读取到的电压值由AD值转化而来。为便于显示小数点后两位电压的数值扩大了100倍 adget_pcf(3);//读取ad V(unsigned int)(ad*100/255*5);//获得当前读取到的电压为方便保留小数点后两位这里已经扩大100倍 读取的处理我放在了定时器里。大致思路如下
1定义一个标志位is_up当读取到的电压值V高于Vp并且is_up0时则将is_up置为1也就是记录第一个状态当前电压值高于Vp
2当当前电压值V低于阈值Vp并且is_up1则将is_up置为0并且计数1.
这样就是实现了只有当电压从高于阈值跳到低于阈值时计数才会1了。具体代码如下 if(is_up0V/10Vp)//如果当前电压V小于Vp则is_up置为1记录此时前一次电压大于Vp的状态 { is_up1; } else if(is_up1V/10Vp)//如果上一次电压V大于Vp且下一次电压V小于Vp则计数1 { is_up0;//记录此时电压小于Vp count;//计数1 } 2.连续按下无效按键的处理
如果是按照我之前写代码的习惯的话我都是在按键处理函数中先读取按键再根据读取到的按键的键值对其进行处理最后将按键的键值清零。
这里对无效的按键处理也用了类似的方法。如果按下了按键并且这个按键被某个if else if语句处理了则将按键的键值清零。如果所有的按键处理都进行完了并且此时按键的键值还不为0则说明按下了一个没有被处理的按键或者说是“无效的按键”因为它没产生任何效果嘛此时记录错误按键次数的标志位count_wrong就1.同时将按键键值清零。如果count_wrong大于三也就是连续三次都按下了无效的按键则将点亮L3的标志位置1题目要求的连续三次无效按键就点亮L3。
至于对于按下有效按键的处理那就好办了只要在按键处理时的每一次处理之后加上count_wrong清零以及将点亮L3的标志位置为0即可。这里就把题目中用到的按键操作也都写出来方便演示对于按下有效按键的处理了。 代码如下 void get_key(void) { unsigned char key_P3P3; unsigned char key_P4P4; static unsigned char count_wrong0;//记录连续多少次按错了按键也就是按下了不被处理的按键 P30xFF; P40xFF; P440; if(P300){Delay5ms();while(P300);Delay5ms();key_value7;} else if(P310){Delay5ms();while(P310);Delay5ms();key_value6;} else if(P320){Delay5ms();while(P320);Delay5ms();key_value5;} else if(P330){Delay5ms();while(P330);Delay5ms();key_value4;} P420; if(P300){Delay5ms();while(P300);Delay5ms();key_value11;} else if(P310){Delay5ms();while(P310);Delay5ms();key_value10;} else if(P320){Delay5ms();while(P320);Delay5ms();key_value9;} else if(P330){Delay5ms();while(P330);Delay5ms();key_value8;} P350; if(P300){Delay5ms();while(P300);Delay5ms();key_value15;} else if(P310){Delay5ms();while(P310);Delay5ms();key_value14;} else if(P320){Delay5ms();while(P320);Delay5ms();key_value13;} else if(P330){Delay5ms();while(P330);Delay5ms();key_value12;} P351; P340; if(P300){Delay5ms();while(P300);Delay5ms();key_value19;} else if(P310){Delay5ms();while(P310);Delay5ms();key_value18;} else if(P320){Delay5ms();while(P320);Delay5ms();key_value17;} else if(P330){Delay5ms();while(P330);Delay5ms();key_value16;} P341; //S12 切换菜单 if(key_value12) { if(mod0) mod1; else if(mod1) { mod2; write_at(0,Vp);//当退出参数界面时记录一次当前Vp参数到AT24C02 } else if(mod2) mod0; key_value0; count_wrong0;//读取到的有效的按键错误按键记录清零下同 is_led3_on0;//熄灭L3 } else if(mod2key_value13) { count0;//情况记录次数 key_value0; count_wrong0; is_led3_on0; } else if(mod1key_value16) { Vp Vp50 ? Vp5:0; key_value0; count_wrong0; is_led3_on0; } else if(mod1key_value17) { VpVp0 ? Vp-5:50; key_value0; count_wrong0; is_led3_on0; } if(key_value!0)//如果走到这一步key_value还不为0则说明读取到的按键未被处理也就是题目上说的无效的按键 { if(count_wrong3) { is_led3_on1; } } key_value0; P3key_P3; P4key_P4; } 3.其他处理
其他大部分处理前面的文章都已经提到了这里一一列举出来并做简单介绍
1对于小数的处理
处理方式就是扩大相应倍数比如要求精确到小数点后一位就把它扩大十倍。同时在Seg_Table修改一下将Seg_Table中10到19显示为0.到9.。显示第一位显示对应的数据10即可把小数点显示出来。具体可以从下边那篇文章中的目录中寻找
蓝桥杯第十四届电子类单片机组程序设计_蓝桥杯单片机哪一届最难-CSDN博客
2对于高位为0时熄灭的处理
我们需要判断这个数的大小主要是位数这里可以用到三目运算符以获得其位数信息。比如对于倒数第三位数码管如果value/100还大于0则说明这位需要显示数据value/100%10也有可能会显示0欧想反如果value/100等于0则这位数码管就需要熄灭而非显示数据.
这样判断可能会消耗一些单片机算力但是我目前还不知道其他有效的方法也欢迎大家不吝赐教。具体介绍可以看下边这篇文章
蓝桥杯第十四届电子类单片机组决赛程序设计_蓝桥杯第十四届单片机资源包-CSDN博客
示例代码 Nixie_num[1]count/100000000 ? count/10000000%10:20; Nixie_num[2]count/10000000 ? count/1000000%10:20; Nixie_num[3]count/1000000 ? count/100000%10:20; Nixie_num[4]count/100000 ? count/10000%10:20; Nixie_num[5]count/10000 ? count/1000%10:20; Nixie_num[5]count/1000 ? count/100%10:20; Nixie_num[6]count/100 ? count/10%10:20; Nixie_num[7]count/10 ? count/1%10:20; 3对于连续5sV小于Vp的处理
总的来说就是当L1标志位为0并且V小于Vp则开始计数当计数够5s了就将L1标志位置为1否则重新计数。 if(is_led1_on0V/10Vp)//如果当前电压小于Vp则开始计数 { if(count_5s5000)//当过来5s当前电压还小于Vp则点亮L1 is_led1_on1; } else//如果不满足上述条件则一切清零重来 { count_5s0; is_led1_on0; } 三、完整代码
main.c
#include stc15.h
#include intrins.h
#include iic.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
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,
0xFF,
0xC1,//U 21
0x8C,//P 22
0xC8,//n 23
};unsigned char Led_Num0xFF;
#define LED_ON(x) Led_Num~(0x01x); P0Led_Num;P2|0x80;P20x9F;P20x1F;
#define LED_OFF(x) Led_Num|0x01x; P0Led_Num;P2|0x80;P20x9F;P20x1F;
#define LED_OFF_ALL() Led_Num0xFF; P0Led_Num;P2|0x80;P20x9F;P20x1F;#define NIXIE_CHECK() P2|0xC0;P20xDF;P20x1F;
#define NIXIE_ON() P2|0xE0;P20xFF;P20x1F;void get_key(void);
void Delay100ms(void); //12.000MHz
void Timer0_Init(void); //1毫秒12.000MHz
void show_menu(void);
void led_run(void);unsigned char location0;//记录当前数码管扫描的位置中间变量
unsigned char key_value0;//记录按键的键值中间变量
unsigned char Nixie_num[]{20,20,20,20,20,20,20,20};//数码管需要显示的数据默认全部熄灭
unsigned char ad0;//读取到的AD值
unsigned char at0;//读取到的AT24C02的值
unsigned char mod0;//菜单0数据采集1参数设置2计数
unsigned char Vp0;//Vp的值已扩大10倍
unsigned char count0;//计数值V从大于Vp到小于Vp一次计数1
unsigned int V0;//当前读取到的电压值由AD值转化而来。为便于显示小数点后两位电压的数值扩大了100倍void main()
{LED_OFF_ALL();Delay100ms();Vpread_at(0);//从AT读取一次VpTimer0_Init();EA1;Delay100ms();while(1){get_key();//读取按键adget_pcf(3);//读取adV(unsigned int)(ad*100/255*5);//获得当前读取到的电压为方便保留小数点后两位这里已经扩大倍show_menu();//显示菜单led_run();//控制LEDDelay100ms();}
}
bit is_up0;//记录上一次电压V是否大于Vp
bit is_led1_on0;//点亮L1
bit is_led3_on0;//点亮L3
unsigned int count_5s0;//数数数5s
void Timer0_Isr(void) interrupt 1
{P00x01location;NIXIE_CHECK();//数码管选择P0Seg_Table[Nixie_num[location]];NIXIE_ON();//数码管显示if(location8)location0;if(is_up0V/10Vp)//如果当前电压V小于Vp则is_up置为1记录此时前一次电压大于Vp的状态{is_up1;}else if(is_up1V/10Vp)//如果上一次电压V大于Vp且下一次电压V小于Vp则计数1{is_up0;//记录此时电压小于Vpcount;//计数1}if(is_led1_on0V/10Vp)//如果当前电压小于Vp则开始计数{if(count_5s5000)//当过来5s当前电压还小于Vp则点亮L1is_led1_on1;}else//如果不满足上述条件则一切清零重来{count_5s0;is_led1_on0;}
}
void Timer0_Init(void) //1毫秒12.000MHz
{AUXR | 0x80; //定时器时钟1T模式TMOD 0xF0; //设置定时器模式TL0 0x20; //设置定时初始值TH0 0xD1; //设置定时初始值TF0 0; //清除TF0标志TR0 1; //定时器0开始计时ET0 1; //使能定时器0中断
}void Delay100ms(void) //12.000MHz
{unsigned char data i, j, k;_nop_();_nop_();i 5;j 144;k 71;do{do{while (--k);} while (--j);} while (--i);
}void Delay5ms(void) //12.000MHz
{unsigned char data i, j;i 59;j 90;do{while (--j);} while (--i);
}void get_key(void)
{unsigned char key_P3P3;unsigned char key_P4P4;static unsigned char count_wrong0;//记录连续多少次按错了按键也就是按下了不被处理的按键P30xFF;P40xFF;P440;if(P300){Delay5ms();while(P300);Delay5ms();key_value7;}else if(P310){Delay5ms();while(P310);Delay5ms();key_value6;}else if(P320){Delay5ms();while(P320);Delay5ms();key_value5;}else if(P330){Delay5ms();while(P330);Delay5ms();key_value4;}P420;if(P300){Delay5ms();while(P300);Delay5ms();key_value11;}else if(P310){Delay5ms();while(P310);Delay5ms();key_value10;}else if(P320){Delay5ms();while(P320);Delay5ms();key_value9;}else if(P330){Delay5ms();while(P330);Delay5ms();key_value8;}P350;if(P300){Delay5ms();while(P300);Delay5ms();key_value15;}else if(P310){Delay5ms();while(P310);Delay5ms();key_value14;}else if(P320){Delay5ms();while(P320);Delay5ms();key_value13;}else if(P330){Delay5ms();while(P330);Delay5ms();key_value12;}P351;P340;if(P300){Delay5ms();while(P300);Delay5ms();key_value19;}else if(P310){Delay5ms();while(P310);Delay5ms();key_value18;}else if(P320){Delay5ms();while(P320);Delay5ms();key_value17;}else if(P330){Delay5ms();while(P330);Delay5ms();key_value16;}P341;//S12 切换菜单if(key_value12){if(mod0)mod1;else if(mod1){mod2;write_at(0,Vp);//当退出参数界面时记录一次当前Vp参数到AT24C02}else if(mod2)mod0;key_value0;count_wrong0;//读取到的有效的按键错误按键记录清零下同is_led3_on0;//熄灭L3}else if(mod2key_value13){count0;//情况记录次数key_value0;count_wrong0;is_led3_on0;}else if(mod1key_value16){Vp Vp50 ? Vp5:0;key_value0;count_wrong0;is_led3_on0;}else if(mod1key_value17){VpVp0 ? Vp-5:50;key_value0;count_wrong0;is_led3_on0;}if(key_value!0)//如果走到这一步key_value还不为0则说明读取到的按键未被处理也就是题目上说的无效的按键{if(count_wrong3){is_led3_on1;}}key_value0;P3key_P3;P4key_P4;
}void show_menu(void)
{if(mod0)//数据读取{Nixie_num[0]21;Nixie_num[1]20;Nixie_num[2]20;Nixie_num[3]20;Nixie_num[4]20;Nixie_num[5]V/100%1010;Nixie_num[6]V/10%10;Nixie_num[7]V/1%10;}else if(mod1)//参数显示{Nixie_num[0]22;Nixie_num[1]20;Nixie_num[2]20;Nixie_num[3]20;Nixie_num[4]20;Nixie_num[5]Vp/10%1010;Nixie_num[6]Vp/1%10;Nixie_num[7]0;}else if(mod2)//记录次数显示{Nixie_num[0]23;//一下处理为让数码管显示count数量并自动调整需要显示的位数Nixie_num[1]count/100000000 ? count/10000000%10:20;Nixie_num[2]count/10000000 ? count/1000000%10:20;Nixie_num[3]count/1000000 ? count/100000%10:20;Nixie_num[4]count/100000 ? count/10000%10:20;Nixie_num[5]count/10000 ? count/1000%10:20;Nixie_num[5]count/1000 ? count/100%10:20;Nixie_num[6]count/100 ? count/10%10:20;Nixie_num[7]count/10 ? count/1%10:20;}
}
bit L1_on0;
bit L2_on0;
bit L3_on0;
void led_run(void)
{if(is_led1_on1L1_on0){LED_ON(0);L1_on1;}else if(is_led1_on0L1_on1){LED_OFF(0);L1_on0;}if(count%21L2_on0)//如果记录的次数为奇数由于这个条件十分简单所以就直接在这里判断了{LED_ON(1);L2_on1;}else if(count%2!1L2_on1){LED_OFF(1);L2_on0; }if(is_led3_on1L3_on0){LED_ON(2);L3_on1;}else if(is_led3_on0L3_on1){LED_OFF(2);L3_on0; }
}iic.c
/* # I2C代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求进行代码调试和修改。
*/#define DELAY_TIME 5
#include stc15.h
#include intrins.h
sbit sdaP2^1;
sbit sclP2^0;
//
static void I2C_Delay(unsigned char n)
{do{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); }while(n--);
}//
void I2CStart(void)
{sda 1;scl 1;I2C_Delay(DELAY_TIME);sda 0;I2C_Delay(DELAY_TIME);scl 0;
}//
void I2CStop(void)
{sda 0;scl 1;I2C_Delay(DELAY_TIME);sda 1;I2C_Delay(DELAY_TIME);
}//
void I2CSendByte(unsigned char byt)
{unsigned char i;for(i0; i8; i){scl 0;I2C_Delay(DELAY_TIME);if(byt 0x80){sda 1;}else{sda 0;}I2C_Delay(DELAY_TIME);scl 1;byt 1;I2C_Delay(DELAY_TIME);}scl 0;
}//
unsigned char I2CReceiveByte(void)
{unsigned char da;unsigned char i;for(i0;i8;i){ scl 1;I2C_Delay(DELAY_TIME);da 1;if(sda) da | 0x01;scl 0;I2C_Delay(DELAY_TIME);}return da;
}//
unsigned char I2CWaitAck(void)
{unsigned char ackbit;scl 1;I2C_Delay(DELAY_TIME);ackbit sda; scl 0;I2C_Delay(DELAY_TIME);return ackbit;
}//
void I2CSendAck(unsigned char ackbit)
{scl 0;sda ackbit; I2C_Delay(DELAY_TIME);scl 1;I2C_Delay(DELAY_TIME);scl 0; sda 1;I2C_Delay(DELAY_TIME);
}unsigned char get_pcf(unsigned char add)
{unsigned char ad0;I2CStart();I2CSendByte(0x90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0x91);I2CWaitAck();adI2CReceiveByte();I2CSendAck(1);I2CStop();return ad;
}void write_at(unsigned char add,dat)
{I2CStart();I2CSendByte(0xA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();
}unsigned char read_at(unsigned char add)
{unsigned char at0;I2CStart();I2CSendByte(0xA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0xA1);I2CWaitAck();atI2CReceiveByte();I2CSendAck(1);I2CStop();return at;
}iic.h
#ifndef _IIC_H_
#define _IIC_H_unsigned char get_pcf(unsigned char add);void write_at(unsigned char add,dat);
unsigned char read_at(unsigned char add);#endif