前言
本次进行蓝桥杯第六届程序编写,本人水平有限,若能提出一些建议可以留言或者私信
一.阅读题目
本届题运用到了串口,eeprom,led闪烁,按键检测,adc转换,RTC实时时钟
led闪烁以及按键检测采用定时器检测,题目如下
看完题有了大体思路,这套题整体来说不是非常的麻烦,比较常规的一道题,题目尚未要求选择时分秒时是否要突出显示,则博主为更好的显示,添加选择时有闪烁突出显示
二.用cubomx进行底层配置
使用TIM2,TIM3定时器进行按键检测,定时时间都为10ms,串口使用pa9和pa10,使用其他引脚需要单独引出转usb与电脑通信
具体cubomx的配置如图所示
三.进行程序编写
本次编写出现了几个细节问题本人的处理方案如下:
本次因为at24c02代码写的时候返回值为int则,存储的时候存入的时k的十倍,读取时除十就好。
问题1:由于题目说初始值为0.1,初始状态at24c02中没有数,则博主在这里用at24c02中第一位作为存储标志,当第一次存储进去的时候,c02的1位也会存储一个数,后面程序进行判断如果1位是相应的数则再进行k值的读取,如果没有的话,那k值就为0.1。
问题2:本题目要求当到达上报时间时就要通过串口进行传输相应文案,但上报时间与RTC时间相等的时间为一秒,串口会发送很多次,所以博主定义一个标志位当发送一次后标志位置1。
注意1:lcd进行界面切换时需要clear一下,由于他是局部刷新则会有上一界面的遗留。
注意2:按键进行操作的时候,每次判断需要手动标志位清零。
注意3:题目尚未要求b4按键具体怎么加减,则博主直接定义为加,加到最大归零。
#include "main.h"
#include "adc.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "i2c_hal.h"
#include "lcd.h"
#include "M24C02.h"
#include "my_ad.h"
#include "my_lcdshow.h"
#include "interrupt.h"
#include "string.h"
#include "stdbool.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define VDD 3.3 //题目VDD宏定义
extern struct key Key_structure[4];
extern char uart_rx[20];
extern unsigned char dat;
extern unsigned char index_rx;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
RTC_TimeTypeDef my_clocktime;//RTC时钟接收时间结构体
RTC_DateTypeDef my_clockdata;//RTC时钟接收日期结构体
/*LCD显示结构体*/
struct lcd_show{
char lcd_line1[20];
char lcd_line2[20];
char lcd_line3[20];
char lcd_line4[20];
}lcd_showstructure = {0,0,0,0};
/*设置上报时间结构体*/
struct time_setting{
unsigned char hour;
unsigned char min;
unsigned char sec;
}time_settingstruct = {0,0,0};
double adc_value = 0;//接收adc转换变量
unsigned char led_state = 0;//控制led是否满足闪烁条件变量
bool led_key_state = 0;//开关led闪烁功能变量
float k = 0.1;//题目k值
unsigned char tx_state = 0;//防止串口一次多发变量
unsigned char lcd_state = 0;//控制lcd显示界面变量
unsigned char choose_value = 1;//设置界面选择时分秒变量
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void lcd_showvalue();//lcd界面显示参数函数
void value_handle();//题目数值处理函数
void uart_autosend();//串口自动发送函数
void lcd_showsetting();//lcd界面显示设置函数
void rx_handle();//串口发送处理函数
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/******************************
*功能:串口发送处理函数
*参数:无
******************************/
void rx_handle()
{
char send_ok[5] = {0};
sprintf((char*)send_ok,"OK\r\n");
if (index_rx)
{
if (index_rx == 4){
sscanf(uart_rx,"k%f",&k);
if (k < 0.9 && k > 0.1){
M24C02_write(0,k * 10);
M24C02_write(1,55);
HAL_UART_Transmit(&huart1,(unsigned char *)send_ok,strlen(send_ok),50);
}
index_rx = 0;
}
}
}
/******************************
*功能:lcd界面显示设置函数
*参数:无
******************************/
void lcd_showsetting()
{
sprintf((char *)lcd_showstructure.lcd_line1," Setting ");
LCD_DisplayStringLine(Line2,(unsigned char*)lcd_showstructure.lcd_line1);
/*进行闪烁*/
switch (choose_value){
case 1:{
sprintf((char *)lcd_showstructure.lcd_line2," %02d - %02d - %02d",time_settingstruct.hour,
time_settingstruct.min,time_settingstruct.sec);
LCD_DisplayStringLine(Line5,(unsigned char*)lcd_showstructure.lcd_line2);
HAL_Delay(200);
sprintf((char *)lcd_showstructure.lcd_line2," - %02d - %02d",time_settingstruct.min,time_settingstruct.sec);
LCD_DisplayStringLine(Line5,(unsigned char*)lcd_showstructure.lcd_line2);
HAL_Delay(200);
break;
}
case 2:{
sprintf((char *)lcd_showstructure.lcd_line2," %02d - %02d - %02d",time_settingstruct.hour,
time_settingstruct.min,time_settingstruct.sec);
LCD_DisplayStringLine(Line5,(unsigned char*)lcd_showstructure.lcd_line2);
HAL_Delay(200);
sprintf((char *)lcd_showstructure.lcd_line2," %02d - - %02d",time_settingstruct.hour,time_settingstruct.sec);
LCD_DisplayStringLine(Line5,(unsigned char*)lcd_showstructure.lcd_line2);
HAL_Delay(200);
break;
}
case 3:{
sprintf((char *)lcd_showstructure.lcd_line2," %02d - %02d - %02d",time_settingstruct.hour,
time_settingstruct.min,time_settingstruct.sec);
LCD_DisplayStringLine(Line5,(unsigned char*)lcd_showstructure.lcd_line2);
HAL_Delay(200);
sprintf((char *)lcd_showstructure.lcd_line2," %02d - %02d - ",time_settingstruct.hour,time_settingstruct.min);
LCD_DisplayStringLine(Line5,(unsigned char*)lcd_showstructure.lcd_line2);
HAL_Delay(200);
break;
}
}
/*end*/
}
/******************************
*功能:串口自动发送函数
*参数:无
******************************/
void uart_autosend()
{
char tx_send[20] = {0};
sprintf(tx_send,"%.2f+%.1f+%02d%02d%02d\r\n",adc_value,k,my_clocktime.Hours,
my_clocktime.Minutes,my_clocktime.Seconds);
HAL_UART_Transmit(&huart1,(unsigned char *)tx_send,strlen(tx_send),50);
tx_state = 1;
}
/******************************
*功能:题目数值处理函数
*参数:无
******************************/
void value_handle()
{
unsigned char state = 0;
state = M24C02_read(1);
if (state != 55)
k = 0.1;
else
k = (float)M24C02_read(0) / 10;
HAL_RTC_GetTime(&hrtc,&my_clocktime,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&my_clockdata,RTC_FORMAT_BIN);
adc_value = adc_get(&hadc2);
if (adc_value > (VDD * k))
led_state = 1;
else led_state = 0;
if (my_clocktime.Hours == time_settingstruct.hour &&
my_clocktime.Minutes == time_settingstruct.min &&
my_clocktime.Seconds == time_settingstruct.sec){
if (!tx_state)//防止一次多发
uart_autosend();
}
else tx_state = 0;
}
/******************************
*功能:lcd界面显示设置函数
*参数:无
******************************/
void lcd_showvalue()
{
value_handle();
sprintf((char *)lcd_showstructure.lcd_line1," V1:%.2f",adc_value);
sprintf((char *)lcd_showstructure.lcd_line2," k:%.1f", k);
if (!led_key_state)
sprintf((char *)lcd_showstructure.lcd_line3," LED:OFF");
else
sprintf((char *)lcd_showstructure.lcd_line3," LED:ON ");
sprintf((char *)lcd_showstructure.lcd_line4," T:%02d-%02d-%02d",my_clocktime.Hours,
my_clocktime.Minutes,my_clocktime.Seconds);
LCD_DisplayStringLine(Line1, (unsigned char *)lcd_showstructure.lcd_line1);
LCD_DisplayStringLine(Line3, (unsigned char *)lcd_showstructure.lcd_line2);
LCD_DisplayStringLine(Line5, (unsigned char *)lcd_showstructure.lcd_line3);
LCD_DisplayStringLine(Line7, (unsigned char *)lcd_showstructure.lcd_line4);
}
/* 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 */
/* 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_RTC_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,&dat,1);
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_Base_Start_IT(&htim2);
I2CInit();
LCD_Init();
LCD_Clear(Blue2);
LCD_SetTextColor(Black);
LCD_SetBackColor(Blue2);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,1);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,1);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,0);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (!lcd_state)
lcd_showvalue();
rx_handle();
if (Key_structure[0].keynum){
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,1);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,1);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,0);
led_key_state = !led_key_state;
Key_structure[0].keynum = 0;
}
if (Key_structure[1].keynum){
LCD_Clear(Blue2);//防止参数界面和设置界面切换时冲突
lcd_state = !lcd_state;
Key_structure[1].keynum = 0;
}
if (lcd_state){
lcd_showsetting();
if (Key_structure[2].keynum){
choose_value++;
if (choose_value > 3)
choose_value = 1;
Key_structure[2].keynum = 0;
}
switch (choose_value){
case 1:{
if (Key_structure[3].keynum){
time_settingstruct.hour++;
if (time_settingstruct.hour >= 24)
time_settingstruct.hour = 0;
Key_structure[3].keynum = 0;
}
break;
}
case 2:{
if (Key_structure[3].keynum){
time_settingstruct.min++;
if (time_settingstruct.min >= 60)
time_settingstruct.min = 0;
Key_structure[3].keynum = 0;
}
break;
}
case 3:{
if (Key_structure[3].keynum){
time_settingstruct.sec++;
if (time_settingstruct.sec >= 60)
time_settingstruct.sec = 0;
Key_structure[3].keynum = 0;
}
break;
}
}
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {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_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
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();
}
}
/* 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 */
__disable_irq();
while (1)
{
}
/* 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,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
中断函数部分
中断服务函数部分每十毫秒进行一遍按键检测,此处为了修复当在界面一的情况下触碰b3b4按键切换界面时会被误判按下了一次,则博主进行判断只有当在设置界面的时候才进行按键b3b4b的扫描,TIM3时进行led的闪烁,因为lcd的影响,如果只控制LD1的,其他的灯也会乱量,所以博主在每次进行闪烁时把PC口全部置1,然后再进行计次对LD1进行单独操作。串口接收,因为每次只能接收到一位所以,要一位一位的接收。
#include "interrupt.h"
#include "usart.h"
#include "stdio.h"
#include "string.h"
/*按键宏定义*/
#define BUTTON_B1 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
#define BUTTON_B2 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
#define BUTTON_B3 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
#define BUTTON_B4 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
/*END*/
/*LED宏定义*/
#define LD1(x) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8,x);
#define LD_ALL(x) HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All,x);
#define LD_START(x) HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2,x);
/*END*/
/*按键结构体*/
struct key{
uint8_t state;//按键的状态
uint8_t keynum;//判断是否成功按下变量
uint8_t count;//消抖变量
};
extern unsigned char lcd_state;
extern unsigned char led_state;
extern unsigned char led_key_state;
struct key Key_structure[4] = {0,0,0};//按键结构体
char uart_rx[20] = {0};//接收串口信息数组
unsigned char index_rx = 0;//串口信息数组指针
unsigned char dat = 0;//串口信息接收变量
float rx_value = 0;//串口提取有效信息返回值
unsigned int led_count = 0;//定时器计时变量
unsigned char led_count_value = 0;//led闪烁奇偶变量
/**********************************************
*功能:TIM2为按键检测,TIM3为LED闪烁计时
*参数:无
***********************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2){
Key_structure[0].state = BUTTON_B1;
Key_structure[1].state = BUTTON_B2;
Key_structure[2].state = BUTTON_B3;
Key_structure[3].state = BUTTON_B4;
if (lcd_state){
for (uint8_t i = 0; i < 4; ++i){
switch(Key_structure[i].count){
case 0:{
if (!Key_structure[i].state)
Key_structure[i].count = 1;
break;
}
case 1:{
if (!Key_structure[i].state){
Key_structure[i].keynum = 1;
Key_structure[i].count = 2;
}
break;
}
case 2:{
if (Key_structure[i].state)
Key_structure[i].count = 0;
break;
}
}
}
}
else{
for (uint8_t i = 0; i < 2; ++i){
switch(Key_structure[i].count){
case 0:{
if (!Key_structure[i].state)
Key_structure[i].count = 1;
break;
}
case 1:{
if (!Key_structure[i].state){
Key_structure[i].keynum = 1;
Key_structure[i].count = 2;
}
break;
}
case 2:{
if (Key_structure[i].state)
Key_structure[i].count = 0;
break;
}
}
}
}
}
else if (htim->Instance == TIM3){
if (led_key_state && led_state){
led_count++;
if (led_count >= 20){
led_count_value++;
LD_START(1);
LD_ALL(1);
if (led_count_value%2){
LD1(1);
}
else
LD1(0);
LD_START(0);
led_count = 0;
}
}
else{
LD_START(1);
LD_ALL(1);
LD_START(0);
}
}
}
/*串口接收*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1){
uart_rx[index_rx++] = dat;
HAL_UART_Receive_IT(&huart1,&dat,1);
}
}
四.总结
本次代码只展示了最重要的两个部分,adc,at24c02等等的配置尚未展出,有需要完整工程的小伙伴可以私信我。