蓝桥杯嵌入式15届模拟一 - 编程解析
·
一题目展示

二代码解析
1、头文件的相关定义与声明
#ifndef _code_h
#define _code_h
#include "stm32g4xx.h" // Device header
#include "stdio.h"
#include "string.h"
#include "stdint.h"
#include "lcd.h"
#include "main.h"
#include "gpio.h"
#include "tim.h"
#include "adc.h"
#include "usart.h"
void lcd_proc(void);
void key_proc(void);
void led_proc(u8 led_x,u8 led_mode);
void usart_proc(void);
double adc_proc(ADC_HandleTypeDef *hadc);
#endif
2、主函数的初始化
#include "code.h"
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
LCD_Init();
LCD_SetTextColor(White);
LCD_SetBackColor(Black);
LCD_Clear(Black);
HAL_TIM_Base_Start(&htim1);
HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_2);
//Cubemx里将TIM15->PSC=8000-1,ARR=100-1,占空比30则设置为30-1
TIM15->CCR2=30-1;
HAL_TIM_IC_Start_IT(&htim16,TIM_CHANNEL_1);
HAL_ADC_Start(&hadc2);
extern u8 my_pData;
HAL_UART_Receive_IT(&huart1,&my_pData,1);
while (1)
{
if(TIM1->CNT%100==0)
lcd_proc();
adc_proc(&hadc2);
key_proc();
usart_proc();
}
3、各个模块的编写
#include "code.h"
double Capture_ccr;
/*---------------------------------------lcd-----------------------------------*/
u8 ui;
u16 N;
char lcd_val[21];
int NH=150;
void lcd_proc(void)
{
led_proc(1,!ui);
led_proc(2,ui);
if(ui==0)
{
sprintf(lcd_val," DATA ");
LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
sprintf(lcd_val," N:%dr/s ",N);
LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
sprintf(lcd_val," D:%.0f%% ",Capture_ccr+1);
LCD_DisplayStringLine(Line4,(u8 *)lcd_val);
sprintf(lcd_val," U:%.1fV ",adc_proc(&hadc2));
LCD_DisplayStringLine(Line5,(u8 *)lcd_val);
sprintf(lcd_val," P:%d",ui+1);
LCD_DisplayStringLine(Line9,(u8 *)lcd_val);
}
else
{
sprintf(lcd_val," PARA ");
LCD_DisplayStringLine(Line1,(u8 *)lcd_val);
sprintf(lcd_val," NH:%d ",NH);
LCD_DisplayStringLine(Line3,(u8 *)lcd_val);
sprintf(lcd_val," P:%d",ui+1);
LCD_DisplayStringLine(Line9,(u8 *)lcd_val);
}
}
/*---------------------------------------key-----------------------------------*/
u8 key_old[4];
u8 key_val[4];
u8 key;
void key_proc(void)
{
for(u8 i=0;i<4;i++)
{
key_val[i]=HAL_GPIO_ReadPin(i<3?GPIOB:GPIOA,GPIO_PIN_0<<i%3);
}
for(u8 i=0;i<4;i++)
{
if(key_val[i]==0&&key_old[i]==1)
{
HAL_Delay(20);
if(key_val[i]==0&&key_old[i]==1)
{
key=i+1;
}
}
}
for(u8 i=0;i<4;i++)
{
key_old[i]=key_val[i];
}
switch(key)
{
case 1:
{
ui=!ui;
LCD_Clear(Black);
break;
}
case 2:
{
if(ui)NH+=50;
if(NH>1000)NH=0;
break;
}
case 3:
{
if(ui)NH-=50;
if(NH<0)NH=1000;
break;
}
case 4:
{
break;
}
}
key=0;
}
/*---------------------------------------led-----------------------------------*/
void led_proc(u8 led_x,u8 led_mode)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
if(led_mode)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led_x-1),GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8<<(led_x-1),GPIO_PIN_SET);
}
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
/*---------------------------------------TIM-----------------------------------*/
u8 it_flag;
double Capture_tim[2];//涉及到小数计算,使用double类型,更加精确一些
u8 led_IT_mode;
//CCER寄存器的bit1可以用来控制输入捕获中断的触发方式
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM16)
{
if(it_flag==0)
{
TIM16->CNT=0;
TIM16->CCER|=0x02;//在cubemx默认bite1为0,即上升沿触发,或为1则设置成下降沿触发
it_flag=1;
}
else if(it_flag==1)
{
Capture_tim[0]=TIM16->CCR1;//记录下降沿此刻时间即为高电平持续时间
TIM16->CCER&=0xFD;//改为上升沿触发
it_flag=2;
}
else if(it_flag==2)
{
Capture_tim[1]=TIM16->CCR1;//此刻时间即为一个PWM波的周期
Capture_ccr=100*Capture_tim[0]/Capture_tim[1];//占空比=高电平持续时间/PWM周期
it_flag=0;
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
led_IT_mode=!led_IT_mode;
}
/*---------------------------------------adc-----------------------------------*/
double adc;
double K;
u8 tx_flag;
double adc_proc(ADC_HandleTypeDef *hadc)
{
HAL_ADC_Start(hadc);
adc=3.3*HAL_ADC_GetValue(hadc)/4095;
if(Capture_ccr<=50)
{
K=-1/0.4*Capture_ccr/100+1.25;
}
else
{
K=1/0.4*Capture_ccr/100-5/4;
}
N=K*adc*1000/5;
if(N>NH&&tx_flag==0)
{
HAL_UART_Transmit(&huart1,(u8 *)"warn",sizeof("warn"),50);
led_proc(3,1);
tx_flag=1;
}
if(N<=NH)
{
led_proc(3,led_IT_mode);
tx_flag=0;
}
return adc;
}
/*---------------------------------------usart-----------------------------------*/
u8 my_pData;
char rx_val[21];
char tx_val[21];
u8 count;
u8 rx_flag;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
rx_val[count]=my_pData;
count++;
rx_flag=1;
TIM2->CNT=0;
HAL_UART_Receive_IT(&huart1,&my_pData,1);
}
void usart_proc(void)
{
if(rx_flag==0)return;
if(TIM2->CNT<50)return;
if(strstr(rx_val,"?")!=NULL)
{
sprintf(tx_val,"%dr/s",N);
HAL_UART_Transmit(&huart1,(u8 *)tx_val,strlen(tx_val),50);
}
else
{
HAL_UART_Transmit(&huart1,(u8 *)"error",strlen("error"),50);
}
rx_flag=0;
count=0;
memset(rx_val,NULL,sizeof(rx_val));
}
三结语
看过我之前的文章的小伙伴可能知道,在之前我串口是有问题,很高兴在今天终于解决了,问题发生在我之前一直以为lcd一行显示最多为20个字符,加上我使用sprintf来对其赋值,之前一直以为sprintf和strcpy不一样,是不会自动赋上结束符的,于是给lcd显示的数组就设置为20,但实际使用时发现当显示完整个数组,使用strlen测量这个数组时是发生了地址越界,所以才会导致串口判断出错,lcd显示数组最小应该也要为21。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)