1 题目
2 解析
cpp
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "stdio.h"
#include "string.h"
#include "i2c_hal.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
RTC_TimeTypeDef sTime;//直接从rtc.c中复制
RTC_DateTypeDef sDate;
char buf[20],buf1[20],buf2[20];//给LCD打印的每行内容存到一个buf里
int hour,min,second;//从串口接收到的上报电压的时间
double k=0.1;
double val;//测得的电位器电压
struct keys{
int step;
int state;
}key[4];//按键
int cnt1,cnt2,cnt3,cnt4;记录每个按键按下的次数
int num=1;//LCD展示的页序号
/* 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 */
void LED_Close()//初始时把所有LED熄灭
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
uint8_t EEPROM_Read(uint8_t addr)//EEPROM读写函数(固定模板)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
uint8_t val=I2CReceiveByte();
I2CWaitAck();
I2CStop();
return val;
}
void EEPROM_Write(uint8_t addr,uint8_t info)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(info);
I2CWaitAck();
I2CStop();
}
double getADC()//测量电位器电压
{
HAL_ADC_Start(&hadc2);
val=HAL_ADC_GetValue(&hadc2)*3.3/4096;
return val;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM8)//给RTC设定一个1s的回调函数,隔一秒打印一次(这里也可以用闹钟中断)
{
HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN);//先获取时间,再获取日期
HAL_RTC_GetDate(&hrtc,&sDate,RTC_FORMAT_BIN);
getADC();//测量电压需要时间,先测量出电压
if(num==1)
{
LCD_ClearLine(Line2);
LCD_ClearLine(Line6);
LCD_DisplayStringLine(Line6,(uint8_t*)buf2);
sprintf(buf," T:%02d-%02d-%02d",sTime.Hours,sTime.Minutes,sTime.Seconds);
LCD_ClearLine(Line7);
LCD_DisplayStringLine(Line7,(uint8_t*)buf);//打印RTC时间
sprintf(buf," V1:%.2lfV",val);
LCD_ClearLine(Line4);
LCD_DisplayStringLine(Line4,(uint8_t*)buf);//打印电压值
sprintf(buf," k:%.1lf",k);
LCD_ClearLine(Line5);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);//打印k值
}
if(hour==sTime.Hours&&min==sTime.Minutes&&second==sTime.Seconds)//如果RTC时间和设定上报电压时间相同,则按照格式上报电压
{
sprintf(buf,"%.2lf+%.1lf+%02d%02d%02d\r\n",val,(double)EEPROM_Read(0x10)/10,hour,min,second);
HAL_UART_Transmit_DMA(&huart1,(uint8_t*)buf,strlen(buf));//串口发送
}
}
if(htim->Instance==TIM1)//间隔0.2s切换LED电平(电压满足条件+监测处于ON状态)
{
if(val>(double)EEPROM_Read(0x10)/10*3.3&&buf2[8]=='N')
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
}
if(htim->Instance==TIM3)//给按键设定一个10ms中断回调函数
{
key[0].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch(key[i].step)
{
case 0:
{
if(key[i].state==GPIO_PIN_RESET)
{
key[i].step=1;
}
}
break;
case 1:
{
if(key[i].state==GPIO_PIN_RESET)
{
if(i==0)
{
if(++cnt1%2==0)//cnt1是偶数,监测ON(默认监测打开);cnt1是奇数,监测OFF
{
sprintf(buf2," LED:ON");
if(num==1)//这是在页面1显示的内容
{
LCD_ClearLine(Line6);
LCD_DisplayStringLine(Line6,(uint8_t*)buf2);
}
}
else
{
/*HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);*/
sprintf(buf2," LED:OFF");
if(num==1)
{
LCD_ClearLine(Line6);
LCD_DisplayStringLine(Line6,(uint8_t*)buf2);
}
}
}
if(i==1)
{
if(++cnt2%2==1)//设定上报时间的页面是页面2
{
num=2;
LCD_Clear(White);
LCD_DisplayStringLine(Line2,(uint8_t*)" Setting ");
sprintf(buf," %02d-%02d-%02d ",hour,min,second);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);
}
else
{
num=1;
}
cnt3=0;
}
if(i==2&&num==2)//只有在页面2时按键PB3才计入,抗干扰
{
cnt3++;
}
if(i==3&&num==2)//只有在页面2时按键PA0才计入,抗干扰
{
if(cnt3%3==0)//进入Setting页面默认调整时
{
hour++;
if(hour==24) hour=0;
LCD_ClearLine(Line5);
sprintf(buf," %02d-%02d-%02d ",hour,min,second);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);
}
if(cnt3%3==1)//按一次为分
{
min++;
if(min==60) min=0;
LCD_ClearLine(Line5);
sprintf(buf," %02d-%02d-%02d ",hour,min,second);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);
}
if(cnt3%3==2)//按两次为秒
{
second++;
if(second==60) second=0;
LCD_ClearLine(Line5);
sprintf(buf," %02d-%02d-%02d ",hour,min,second);
LCD_DisplayStringLine(Line5,(uint8_t*)buf);
}
}
key[i].step=2;
}
else
{
key[i].step=0;
}
}
break;
case 2:
{
if(key[i].state==GPIO_PIN_SET)
{
key[i].step=0;
}
}
break;
}
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)//串口中断回调函数,接收到一次上报电压的数据就回复一次ok
{
sscanf(buf1,"k%lf\r\n",&k);
EEPROM_Write(0x10,(uint8_t)(10*k));
HAL_UART_Transmit_DMA(&huart1,(uint8_t*)"ok\r\n",4);
HAL_UART_Receive_DMA(&huart1,(uint8_t*)buf1,6);
}
}
/* 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_DMA_Init();
MX_RTC_Init();
MX_TIM1_Init();
MX_TIM8_Init();
MX_USART1_UART_Init();
MX_ADC2_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
I2CInit();
HAL_TIM_Base_Start_IT(&htim8);
HAL_TIM_Base_Start_IT(&htim1);
HAL_TIM_Base_Start_IT(&htim3);
LCD_Init();
LED_Close();
LCD_Clear(White);
LCD_SetBackColor(White);
LCD_SetTextColor(Black);
if(EEPROM_Read(0x99)!=2)//监测板子是不是第一次上电
{
EEPROM_Write(0x99,2);
HAL_Delay(20);
EEPROM_Write(0x10,1);
}
HAL_UART_Receive_DMA(&huart1,(uint8_t*)buf1,6);
sprintf(buf2," LED:ON");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}