14届蓝桥杯嵌入式国赛
14届蓝桥杯嵌入式决赛现场版代码
14届蓝桥杯嵌入式国赛
楼主为13届蓝桥杯单片机组国二得主,14届参加蓝桥杯嵌入式组决赛,分享比赛代码如下。
硬件框图
总体框架较为简单,考到了DS18B20、单路PWM捕获、ADC采集、PWM生成等模块。细节上东西比较多,处理记录波形和产生波形的时序、温度的温定读取、双按键长按、时间准确控制等。
14届国赛省赛都在PWM生成上作文章,控制好变化时间还是可以很丝滑的,楼主把PWM控制放在了systick中断里,采集播放脉冲、电压信号效果较好。
以下代码为楼主上午在现场写的,时间较紧张没有写注释,仅给出main.c文件(基本都在main.c实现),有bug和不足之处请大家指出!!!
CubeMX配置
按键,LED,LCD;PA1是PWM采集,PA7是PWM输出,PB15采集R37,单总线PA6直接移植。
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "stdio.h"
#include "ds18b20_hal.h"
#include "key.h"
#include "led.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
float volt_r37,volt_r37_last;
float temp,temp_last;
u16 adc_val;
u8 interface;
//interface 2
u16 FH=2000,FH_set=2000;
float AH=3.0,AH_set=3.0;
u8 TH=30,TH_set=30;
//interface 3
u8 FN,AN,TN;
//interface 4
u8 FP=1,FP_set=1;
float VP=0.9,VP_set=0.9;
u8 TT=6,TT_set=6;
//1.ADC
void ADC_Process()
{
HAL_ADC_Start(&hadc2);
adc_val = HAL_ADC_GetValue(&hadc2);
volt_r37_last = volt_r37;
volt_r37 = adc_val/4095.0f*3.3f;
if(volt_r37>AH_set&&volt_r37_last<AH_set)
AN++;
}
//2.PWM IC
u8 state_tim2;
u16 cnt1_tim2,cnt2_tim2;
u16 freq_PA1_r,freq_PA1,freq_PA1_last;
u8 duty_PA1_R,duty_PA1;
u32 freq;
u8 i;
u16 duty;
u8 j;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(state_tim2==0)
{
__HAL_TIM_SetCounter(&htim2,0);
TIM2->CCER |= 0x02;
state_tim2 =1;
}
else if(state_tim2==1)
{
cnt1_tim2 = __HAL_TIM_GetCounter(&htim2);
TIM2->CCER &= ~0x02;
state_tim2 =2;
}
else if(state_tim2==2)
{
cnt2_tim2 = __HAL_TIM_GetCounter(&htim2);
state_tim2 =0;
freq_PA1_last = freq_PA1;
freq_PA1_r = 1e6/cnt2_tim2;
duty_PA1_R = cnt1_tim2*100.0f/cnt2_tim2;
if(++i<60)
freq+=freq_PA1_r;
else if(i==60)
{
i=0;
freq_PA1 = freq/(60-1);
freq=0;
}
if(++j<100)
duty+=duty_PA1_R;
else if(j==100)
{
j=0;
duty_PA1 = duty/(100-1);
duty=0;
}
if(freq_PA1>FH_set&&freq_PA1_last<=FH_set)
FN++;
}
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
}
//3.Temp
__IO u16 temp_tick;
void Temp_Process()
{
temp_last =temp;
temp = ds18b20_read();
if(temp>TH_set&&temp_last<TH_set)
TN++;
}
//4.LCD
void LCD_Process()
{
u8 lcd_buff[20];
if(interface==0)
{
sprintf((char *)lcd_buff," DATA ");
LCD_DisplayStringLine(Line1, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," F=%d ",freq_PA1);
LCD_DisplayStringLine(Line3, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," D=%d%% ",duty_PA1);
LCD_DisplayStringLine(Line4, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," A=%3.1f ",volt_r37);
LCD_DisplayStringLine(Line5, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," T=%3.1f ",temp);
LCD_DisplayStringLine(Line6, (unsigned char *)lcd_buff);
}
else if(interface==1)
{
sprintf((char *)lcd_buff," PARA ");
LCD_DisplayStringLine(Line1, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," FH=%d ",FH);
LCD_DisplayStringLine(Line3, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," AH=%3.1f ",AH);
LCD_DisplayStringLine(Line4, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," TH=%d ",TH);
LCD_DisplayStringLine(Line5, (unsigned char *)lcd_buff);
LCD_DisplayStringLine(Line6, (unsigned char *)" ");
}
else if(interface==2)
{
sprintf((char *)lcd_buff," RECD ");
LCD_DisplayStringLine(Line1, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," FN=%d ",FN);
LCD_DisplayStringLine(Line3, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," AN=%d ",AN);
LCD_DisplayStringLine(Line4, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," TN=%d ",TN);
LCD_DisplayStringLine(Line5, (unsigned char *)lcd_buff);
LCD_DisplayStringLine(Line6, (unsigned char *)" ");
}
else if(interface==3)
{
sprintf((char *)lcd_buff," FSET ");
LCD_DisplayStringLine(Line1, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," FP=%d ",FP);
LCD_DisplayStringLine(Line3, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," VP=%-3.1f ",VP);
LCD_DisplayStringLine(Line4, (unsigned char *)lcd_buff);
sprintf((char *)lcd_buff," TT=%d ",TT);
LCD_DisplayStringLine(Line5, (unsigned char *)lcd_buff);
LCD_DisplayStringLine(Line6, (unsigned char *)" ");
}
}
//record
u16 freq_r[101];
u8 duty_r[101];
u8 duty_Adc[101];
_Bool flag_Record;
u16 cnt_Record;
u8 cnt_index;
u16 cnt_KB34;
_Bool flag_K34;
_Bool flag_pwm;
_Bool flag_adc;
_Bool flag_jilu;
u8 led;
u8 led_cnt;
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
if(flag_K34)
{
if(++cnt_KB34>2000)
{
cnt_KB34=0;
key_lock=1;
flag_K34=0;
interface=0;
FH_set=FH=2000;
AH_set=AH=3.0f;
TH_set=TH=30;
FP_set=FP=1;
VP_set=VP=0.9f;
TT_set=TT=6;
FN=AN=TN=0;
}
}
if(++temp_tick>750)
{
temp_tick = 0;
Temp_Process();
}
if(flag_Record)
{
if(++cnt_Record>1000*TT_set)
{
cnt_Record=0;
flag_Record=0;
cnt_index=0;
flag_jilu=1;
}
if(cnt_Record%100==0)//0.1s
{
freq_r[cnt_index]=freq_PA1;
duty_r[cnt_index]=duty_PA1;
if(volt_r37>=VP_set)
duty_Adc[cnt_index]=90.0f/(3.3f-VP_set)*(volt_r37-3.3f)+100.0f;
else
duty_Adc[cnt_index]=10;
cnt_index++;
}
if(++led_cnt==100)
{
led^=0x01;
led_cnt=0;
}
}
else
led&=~0x01;
if(flag_pwm)
{
if(++cnt_Record>1000*TT_set)
{
cnt_Record=0;
flag_pwm=0;
cnt_index=0;
}
if(cnt_Record%100==0)//0.1s
{
TIM17->ARR=1e6/freq_r[cnt_index]*FP_set-1;
TIM17->CCR1=duty_r[cnt_index]*(1e6/freq_r[cnt_index]*FP_set)/100.0f;
cnt_index++;
}
if(cnt_Record==0)
{
TIM17->CCR1=0;
}
if(++led_cnt==100)
{
led_cnt=0;
led^=0x02;
}
}
else
led&=~0x02;
if(flag_adc)
{
if(++cnt_Record>1000*TT_set)
{
cnt_Record=0;
flag_adc=0;
cnt_index=0;
}
if(cnt_Record%100==0)//0.1s
{
TIM17->ARR=999;
TIM17->CCR1=duty_Adc[cnt_index]*10.0f;
cnt_index++;
}
if(cnt_Record==0)
{
TIM17->CCR1=0;
}
if(++led_cnt==100)
{
led_cnt=0;
led^=0x04;
}
}
else
led&=~0x04;
/* USER CODE END SysTick_IRQn 1 */
}
//4.Key
u8 flag_interface1,flag_interface3;
__IO u32 key_tick;
void Key_Process()
{
if(uwTick - key_tick<10) return;
key_tick = uwTick;
Scan_Key();
if(flag_Record) return;
if(!Cnt)
{
key_lock =0;
cnt_KB34=0;
flag_K34=0;
}
if(Cnt&0x0c)
{
flag_K34=1;
}
if(Trg&0x01)
{
if(++interface==4)
interface=0;
if(interface==2)
{
FH_set = FH;
AH_set = AH;
TH_set = TH;
}
else if(interface==0)
{
FP_set = FP;
VP_set = VP;
TT_set = TT;
}
else if(interface==1)
{
flag_interface1=0;
}
else if(interface==3)
{
flag_interface3=0;
}
}
else if(Trg&0x02)
{
if(interface==0)//Record
{
flag_Record=1;
led_cnt=0;
}
else if(interface==1)
{
if(++flag_interface1==3)
flag_interface1=0;
}
else if(interface==2)
{
FN=AN=TN=0;
}
else if(interface==3)
{
if(++flag_interface3==3)
flag_interface3=0;
}
}
else if(Trg&0x04)
{
if(interface==1)
{
if(flag_interface1==0)
{
if(FH<10000)
FH+=1000;
}
else if(flag_interface1==1)
{
if(AH<3.2f)
AH+=0.3f;
}
else if(flag_interface1==2)
{
if(TH<80)
TH+=1;
}
}
else if(interface==3)
{
if(flag_interface3==0)
{
if(FP<10)
FP+=1;
}
else if(flag_interface3==1)
{
if(VP<3.2f)
VP+=0.3f;
}
else if(flag_interface3==2)
{
if(TT<10)
TT+=2;
}
}
else if(interface==0)
{
if(!flag_pwm&&flag_jilu)
{
flag_adc=1;
led_cnt=0;
}
}
}
else if(Trg&0x08)
{
if(interface==1)
{
if(flag_interface1==0)
{
if(FH>1000)
FH-=1000;
}
else if(flag_interface1==1)
{
if(AH>0.2f)
AH-=0.3f;
}
else if(flag_interface1==2)
{
if(TH>0)
TH-=1;
}
}
else if(interface==3)
{
if(flag_interface3==0)
{
if(FP>1)
FP-=1;
}
else if(flag_interface3==1)
{
if(VP>0.5f)
VP-=0.3f;
else
VP=0;
}
else if(flag_interface3==2)
{
if(TT>2)
TT-=2;
}
}
else if(interface==0)
{
if(!flag_adc&&flag_jilu)
{
flag_pwm=1;
led_cnt=0;
}
}
}
}
//5.LED
void LED_Process()
{
LED_Contr(led);
if(freq_PA1>FH_set)
led|=0x08;
else
led&=~0x08;
if(volt_r37>AH_set)
led|=0x10;
else
led&=~0x10;
if(temp>TH_set)
led|=0x20;
else
led&=~0x20;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC2_Init();
MX_TIM2_Init();
MX_TIM17_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
ds18b20_init_x();
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
TIM17->CCR1 = 0;//high 0
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
while((u8)ds18b20_read()==85)
{
}
temp = ds18b20_read();
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
ADC_Process();
LCD_Process();
Key_Process();
LED_Process();
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12;
PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
代码细节解释
1. 双按键长按
使用上升沿触发,三行按键写法如下:
#include "key.h"
#define KB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KB3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KB4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define Key_Port (KB1)|(KB2<<1)|(KB3<<2)|(KB4<<3)|0xf0
u8 Trg;
u8 Cnt;
_Bool key_lock;
void Scan_Key(void)
{
u8 Read_Dat = (Key_Port)^0xff;
if(key_lock==0)
Trg = Cnt&(Read_Dat^Cnt);
Cnt = Read_Dat;
}
由于是KB3+KB4一起长按1s,需要判断两位0000 1100 即0x0c(通过仿真调试也可以验证)。
2. PWM和ADC数据记录
第一眼拿到赛题对信号记录的感觉是懵的,后来转念一想,这不就是按照同样时间频率进行打点计数嘛,于是我采用了数组计数,没有对动态内存作优化,直接定义100个字长的数组!每0.1s进行一次计数。
具体实现在main.h里面的systemtick回调函数里面(所有时间要求准操作的我都放在这里面了),实现思路就是定义变量自加取模。
3. 信号发生
直接操作寄存器,简洁了当。
TIM17->ARR;
TIM17->CCR1
这个过程其实和上个过程是反的,只需要倒过来赋值就可以了。
下面是我systemtick回调函数里的内容:
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
if(flag_K34)
{
if(++cnt_KB34>2000)
{
cnt_KB34=0;
key_lock=1;
flag_K34=0;
interface=0;
FH_set=FH=2000;
AH_set=AH=3.0f;
TH_set=TH=30;
FP_set=FP=1;
VP_set=VP=0.9f;
TT_set=TT=6;
FN=AN=TN=0;
}
}
if(++temp_tick>750)
{
temp_tick = 0;
Temp_Process();
}
if(flag_Record)
{
if(++cnt_Record>1000*TT_set)
{
cnt_Record=0;
flag_Record=0;
cnt_index=0;
flag_jilu=1;
}
if(cnt_Record%100==0)//0.1s
{
freq_r[cnt_index]=freq_PA1;
duty_r[cnt_index]=duty_PA1;
if(volt_r37>=VP_set)
duty_Adc[cnt_index]=90.0f/(3.3f-VP_set)*(volt_r37-3.3f)+100.0f;
else
duty_Adc[cnt_index]=10;
cnt_index++;
}
if(++led_cnt==100)
{
led^=0x01;
led_cnt=0;
}
}
else
led&=~0x01;
if(flag_pwm)
{
if(++cnt_Record>1000*TT_set)
{
cnt_Record=0;
flag_pwm=0;
cnt_index=0;
}
if(cnt_Record%100==0)//0.1s
{
TIM17->ARR=1e6/freq_r[cnt_index]*FP_set-1;
TIM17->CCR1=duty_r[cnt_index]*(1e6/freq_r[cnt_index]*FP_set)/100.0f;
cnt_index++;
}
if(cnt_Record==0)
{
TIM17->CCR1=0;
}
if(++led_cnt==100)
{
led_cnt=0;
led^=0x02;
}
}
else
led&=~0x02;
if(flag_adc)
{
if(++cnt_Record>1000*TT_set)
{
cnt_Record=0;
flag_adc=0;
cnt_index=0;
}
if(cnt_Record%100==0)//0.1s
{
TIM17->ARR=999;
TIM17->CCR1=duty_Adc[cnt_index]*10.0f;
cnt_index++;
}
if(cnt_Record==0)
{
TIM17->CCR1=0;
}
if(++led_cnt==100)
{
led_cnt=0;
led^=0x04;
}
}
else
led&=~0x04;
/* USER CODE END SysTick_IRQn 1 */
}
实现了长按处理,温度采集,信号采集,信号播放功能。
4.PWM频率和占空比采集
简单在状态机里面写了个滤波,防止报警值不稳定。
else if(state_tim2==2)
{
cnt2_tim2 = __HAL_TIM_GetCounter(&htim2);
state_tim2 =0;
freq_PA1_last = freq_PA1;
freq_PA1_r = 1e6/cnt2_tim2;
duty_PA1_R = cnt1_tim2*100.0f/cnt2_tim2;
if(++i<60)
freq+=freq_PA1_r;
else if(i==60)
{
i=0;
freq_PA1 = freq/(60-1);
freq=0;
}
if(++j<100)
duty+=duty_PA1_R;
else if(j==100)
{
j=0;
duty_PA1 = duty/(100-1);
duty=0;
}
if(freq_PA1>FH_set&&freq_PA1_last<=FH_set)
FN++;
}
5.其他一些注意的逻辑
- 切换界面参数才生效,我设置了两对变量
- 只要采集了才能生成PWM,用一个标志位处理
- ds18b20温度采集放在while(1)里面容易跑飞,我放在中断
- 数组处理好别越界
hex文件
如代码包所示,工程文件可以私信楼主获取,有任何问题欢迎友友们指出评论!!!
更多推荐
所有评论(0)