蓝桥杯嵌入式架构(待更新)

蓝桥杯嵌入式架构(待更新) 一、问题之前用dwt测试了一下lcd刷新一次大概需要40-60mslcd放在main跑只要这个50-60ms期间出现了任何中断就会出现噪点4t测评出来是0分所以lcd适合不能被打断的环节可以临时关闭中断但是有概率出现其他中断刚好被漏了风险很大有没有一个解决办法呢二、方案定时器就特别适合它我只要开一个定时器优先级为1串口的中断优先级设置为0不就解决被打断的问题了吗我一般会选择定时器1来做这个事情我设置的20ms触发一次中断在这个定时器的回调函数里面跑赛题上面的服务这样就实现了一个简单的时间片。有人会问了你刚才不是说了吗lcd刷新一次再这么也需要40ms你给20ms的定时器咋跑上一个中断还没跑完呢下一个中断就触发了不会乱跑吗完全不会有问题我们设置定时器跑程序目的就是写出一个不会被打断的main函数并且一直循环。就只解决一个lcd不出噪点的痛点吗这个写法可没那么弱看到上面的key_judge没有猜猜这是啥里面有key_scan扫描状态我们的机械抖动区间是多少毫秒呢很垃圾的品牌也小于30ms平时用的一般在10到20ms我们这一轮程序需要多少ms呢那些代码逻辑不会超过10mslcd最小40ms最大60ms加起来的区间在50ms到60ms是吧拿来给按键滤波简直完美2次判断key的值的时间差只要不超过100ms不可能出现漏判并且响应还算比较灵敏只要不在里面放delay不可能一个周期超过100ms那我们的key要求的是啥呢我见过最快的一套题是0.1s内反应完美解决三、代码模板分享与讲解1.key_scanGPIO_TypeDef * key[4]{GPIOB,GPIOB,GPIOB,GPIOA}; uint8_t key_offset[4]{0x01,0x011,0x012,0x01}; uint8_t key_old_value[4]{0}; uint8_t key_new_value[4]{0}; void key_scan() { for(uint8_t i0;i4;i) { key_old_value[i]key_new_value[i]; key_new_value[i]key[i]-IDRkey_offset[i]?1:0; } }可以把这几个key的端口和偏移量存起来用for一把梭IDR这个寄存器是啥呢就是输入捕获寄存器可以用它来检测输入状态我这个代码的意思是如果这个按钮被按下了那就是0没按下就是1如何判断按钮刚按下呢old_value是1new_value是0也就是刚按下的瞬间old_value是0new_value是1也就是刚释放的瞬间old_value是0new_value是0也就是持续按住void key_judge() { key_scan(); if(key_old_value[0]1key_new_value[0]0) { } else if(key_old_value[1]1key_new_value[1]0) { } else if(key_old_value[2]1key_new_value[2]0) { } else if(key_old_value[3]1key_new_value[3]0) { }在里面填入逻辑就行了题目让干啥就在里面写啥2.下面是ui_refreshui刷新uint8_t page_index1;//初始化page_index题目肯定会让默认上电后在哪个界面那个界面就是index为1 void ui_refresh() { switch(page_index) { case 1: page1(); break; case 2: page2(); break; case 3: page3(); break; } }还是完形填空那一套看题目有几个page界面就写几个每写了一个小功能立马下进去看看测试完成才往下走这样你出错了错误永远在你的上一步这一步是所有里面最重要的并且最好是下载得越频繁越好我一般写几句话就编译看看然后下载进去测试反正5个小时这样做实际上3个小时不到就能做完。3.adc_judgefloat adc_value0.0f; void adc_judge() { adc_valueADC1-DR/65535.0*3.3;//读取出来你们一般 //看你们设置的adc精度你们一般用的12位除以4095.0就行了我开了过采样是16位精度需要除以65535.0 //这里放题目要求的任务比如adc小于1v那就写个if放这里处理 HAL_ADC_Start_IT(hadc1);//读取完成后记得再次打开 }4.led(1)这个是我的led的驱动void led_show(uint16_t temp) { HAL_GPIO_WritePin(le_GPIO_Port,le_Pin,0); GPIOC-ODR0x00ff; GPIOC-ODR|~(temp8); HAL_GPIO_WritePin(le_GPIO_Port,le_Pin,1); HAL_GPIO_WritePin(le_GPIO_Port,le_Pin,0); }我的le是PD2引脚第一行你们写GPIOD,GPIO_PIN_2,0就行了最后两行一样的ODR是输出寄存器16个bit我们的led在高八位所以要偏移过去因为led板子上接的低电平点亮这样能提高灌电流能力也就是更亮所以GPIOC-ODR|~(temp8); 对temp进行了取反写起来更爽0x01就是led1亮聪明的你会问led8咋办呢0x017(2)这个是led_judgevoid led_judge() { static uint8_t led_out0x00;//头 if(MODE1){led_out|0x01;}else {led_out~(0x01);} if(LOCK1){led_out|0x011;}else {led_out~(0x011);} if(!(adc_valuePU_yesPD_yesadc_value)){led_out|0x012;}else {led_out~(0x012);} led_show(led_out);//尾 }利用static创建一次后后续不会再次创建的原理也就是 static uint8_t led_out0x00;这句话不管函数执行多少次只有第一次执行了其他时候直接绕过我们可以写一个流水线先写个头通过逻辑加工后在尾巴送给led5.dwt!!!void DWT_Init(void) { CoreDebug-DEMCR | (1UL 24); // 开启调试时钟 DWT-CYCCNT 0; // 清零计数器 DWT-CTRL | (1UL 0); // 使能 CYCCNT }为什么我会强调这个东西呢定时器我们设置的20ms但是跑一次需要大于50ms那么用定时器计数来实现一个倒计时是不是不太准确啊我之前也遇到过这个坑要求我3s后跳转到另外一个界面我等了10来秒才跳转有没有办法解决呢dwt就是破局之法dwt这玩意是独立计时的我们开机的时候把dwt_init放在main里面初始化一次就行后续使用的时候像我这样写//80mhz就是80后面跟6个080mhz就是1秒来这么多个脉冲我要定时1.5秒就只用把他乘以1.5这里必须要用大于等于不要等于这个东西计时贼快判断的时候总会大于的我们执行周期是ms它的计数周期可是纳秒级别 DWT-CYCCNT0;//刚刚开始使用的时候把计数器清空这个计数器是一个32位的大概在42秒后就溢出了我们的按键或者事件谁发神经长按或者等待大于半分钟啊 if(DWT-CYCCNT80000000*1.5) { LOCK1; } else { LOCK0; }