硬件框图
CubeMX配置
1、SYS 中的 Debug 设置为 Serial Wire
2、RCC 中的 HSE 设置为 Crystal/Ceramic Resonator
3、时钟树
4、配置LED灯的引脚(PB8 — PB15)为推挽输出,初始化为高电平
5、配置PD2为输出,保证led的功能正常运行
6、LCD的引脚可以不用在CubeMX中配置,资料包里的 lcd.c 中有对相应引脚的配置
7、配置按键的引脚(PB0、PB1、PB2、PA0 —— B1、B2、B3、B4)为输入并设置为上拉
8、配置定时器TIM4去扫描按键
9、电压采集1 的引脚为 PB15 对应ADC2_IN15
keil里的一些设置
代码编写
1、创建一个文件夹bsp用于存放各模块的 .c 和 .h 文件
2、将创建的文件夹路径加载进 “include path” 中
3、新建分组,并将用到的文件引入
LED
#include "led.h"
uint16_t LED_Val;
//描述:关闭所有LED
void Off_LEDs(void)
{
LED_Val |= (0xff<<8);
GPIOC->ODR = (uint32_t)LED_Val;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
//描述:开启所有LED
void On_LEDs(void)
{
LED_Val &= ~(0xff<<8);
GPIOC->ODR = (uint32_t)LED_Val;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
//描述:开启指定的LED,输入的参数为(1~8)
void TurnOn_LED(uint8_t led)
{
LED_Val &= ~(0x01<<(7+led));
GPIOC->ODR = (uint32_t)LED_Val;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
//描述:关闭指定的LED,输入的参数为(1~8)
void TurnOff_LED(uint8_t led)
{
LED_Val |= (0x01<<(7+led));
GPIOC->ODR = (uint32_t)LED_Val;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
注:初始化时,要将LED灯全部关闭
Off_LEDs();
KEY
创建 interrupt.c 和 interrupt.h
interrupt.c
#include "interrupt.h"
struct key keys[4]={0,0,0,0}; //定义4个按键
// 80M/80/10000=100Hz,即10ms进入一次中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4)
{
//分别读取4个按键的状态
keys[0].key_sta = KB1;
keys[1].key_sta = KB2;
keys[2].key_sta = KB3;
keys[3].key_sta = KB4;
for(int i=0; i<4; i++)
{
switch(keys[i].judge_sta)
{
//第一阶段:进入按键,先进行消抖
case 0:
if(keys[i].key_sta == 0)
{
keys[i].judge_sta = 1;
}
break;
//第二阶段:经过消抖后,确定已经处于稳定状态
case 1:
if(keys[i].key_sta == 0)
{
keys[i].judge_sta = 2;
}
else
{
keys[i].judge_sta = 0;
}
break;
//第三阶段:等待按键被抬起,设置按键标志位
case 2:
if(keys[i].key_sta == 1)
{
keys[i].judge_sta = 0;
keys[i].single_flag = 1;
}
break;
}
}
}
}
interrupt.h
#ifndef __INTERRUPT_H
#define __INTERRUPT_H
#include "main.h"
#include "stdbool.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)
struct key
{
unsigned char judge_sta; //判断按键处于那个阶段(消抖、稳定、抬起)
bool key_sta; //按键输入引脚此时的状态
bool single_flag; //单击按键的标志位
};
#endif
注:初始化时,要开启定时器TIM4中断
HAL_TIM_Base_Start_IT(&htim4); //开启TIM4的时钟中断——扫描按键
LCD
将资料包里LCD例程中的 lcd.c、lcd.h、fonts.h 移植到自己项目中的 bsp
注:初始化时,将LCD屏的初始状态设置为黑屏,黑底白字
LCD_Init(); //初始化LCD
LCD_Clear(Black); //将LCD清空为黑屏
LCD_SetBackColor(Black); //背景色——黑色
LCD_SetTextColor(White); //文字色——白色
ADC
创建bsp_adc.c 和 bsp_adc.h
#include "bsp_adc.h"
//描述:获取ADC数据
uint16_t getADC(ADC_HandleTypeDef *hadc)
{
uint16_t adc;
HAL_ADC_Start(hadc);
adc = HAL_ADC_GetValue(hadc);
return adc;
}
注:初始化时,校准ADC2
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
main.c
1、定义变量
int view = 0;
int options = 0;
float max_volt = 2.4, min_volt = 1.2;
int upper_val = 1, lower_val = 2;
float adc = 0;
extern struct key keys[4];
2、在main函数的while中主要执行对 LED 灯、LCD显示屏、按键的控制,所以分别编写相应的函数
LCD显示屏控制
//LCD显示屏控制函数
void disp_proc(void)
{
char text[30];
switch(view)
{
//Main界面
case 0:
memset(text,0x00,30);
sprintf(text," Main ");
LCD_DisplayStringLine(Line1,(uint8_t *)text);
adc = (float)getADC(&hadc2)*3.3/4095;
sprintf(text," Volt: %.2fV",adc);
LCD_DisplayStringLine(Line3,(uint8_t *)text);
if(adc>max_volt)
LCD_DisplayStringLine(Line5,(unsigned char *)" Status:Upper ");
else if(adc<min_volt)
LCD_DisplayStringLine(Line5,(unsigned char *)" Status:Lower ");
else
LCD_DisplayStringLine(Line5,(unsigned char *)" Status:Normal ");
break;
//Setting界面
case 1:
memset(text,0x00,30);
sprintf(text," Setting ");
LCD_DisplayStringLine(Line1,(uint8_t *)text);
//对选中部分进行高亮判断
sprintf(text," Max Volt: %.1fV ",max_volt);
if(options == 1) LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line3,(uint8_t *)text);
LCD_SetBackColor(Black);
sprintf(text," Min Volt: %.1fV ",min_volt);
if(options == 2) LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
LCD_SetBackColor(Black);
sprintf(text," Upper: LD%d ",upper_val);
if(options == 3) LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line5,(uint8_t *)text);
LCD_SetBackColor(Black);
sprintf(text," Lower: LD%d ",lower_val);
if(options == 4) LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line6,(uint8_t *)text);
LCD_SetBackColor(Black);
break;
}
}
按键控制
//按键控制函数
void key_proc(void)
{
if(keys[0].single_flag == 1)
{
view++;
if(view == 2)
view = 0;
keys[0].single_flag = 0;
LCD_Clear(Black);
options = 0;
}
if(view == 1)
{
if(keys[1].single_flag == 1)
{
options++;
if(options == 5)
options = 1;
keys[1].single_flag = 0;
}
switch (options)
{
case 1:
if(keys[2].single_flag == 1)
{
max_volt += 0.3;
if(max_volt>3.3)
max_volt = 3.3;
keys[2].single_flag = 0;
}
if(keys[3].single_flag == 1)
{
max_volt -= 0.3;
if(max_volt < min_volt)
max_volt += 0.3;
keys[3].single_flag = 0;
}
break;
case 2:
if(keys[2].single_flag == 1)
{
min_volt += 0.3;
if(min_volt > max_volt)
{
min_volt -= 0.3;
}
keys[2].single_flag = 0;
}
if(keys[3].single_flag == 1)
{
min_volt -= 0.3;
if(min_volt < 0)
min_volt = 0;
keys[3].single_flag = 0;
}
break;
case 3:
if(keys[2].single_flag == 1)
{
upper_val++;
if(upper_val>8)
upper_val = 1;
if(upper_val==lower_val)
{
if(upper_val == 8)
upper_val = 1;
else
upper_val++;
}
keys[2].single_flag = 0;
}
if(keys[3].single_flag == 1)
{
upper_val--;
if(upper_val<1)
upper_val = 8;
if(upper_val==lower_val)
{
if(upper_val == 1)
upper_val = 8;
else
upper_val--;
}
keys[3].single_flag = 0;
}
break;
case 4:
if(keys[2].single_flag == 1)
{
lower_val++;
if(lower_val>8)
lower_val = 1;
if(upper_val==lower_val)
{
if(lower_val == 8)
lower_val = 1;
else
lower_val++;
}
keys[2].single_flag = 0;
}
if(keys[3].single_flag == 1)
{
lower_val--;
if(lower_val<1)
lower_val = 8;
if(upper_val==lower_val)
{
if(lower_val == 1)
lower_val = 8;
else
lower_val--;
}
keys[3].single_flag = 0;
}
break;
}
}
}
LED控制
//LED控制函数
void led_proc(void)
{
adc = (float)getADC(&hadc2)*3.3/4095;
if(adc>max_volt)
{
TurnOn_LED(upper_val);
HAL_Delay(200);
TurnOff_LED(upper_val);
HAL_Delay(200);
}
else if(adc<min_volt)
{
TurnOn_LED(lower_val);
HAL_Delay(200);
TurnOff_LED(lower_val);
HAL_Delay(200);
}
}
主函数中
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_TIM4_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
LCD_Init(); //初始化LCD
Off_LEDs(); //关闭全部LED
LCD_Clear(Black); //将LCD清空为黑屏
LCD_SetBackColor(Black); //背景色——黑色
LCD_SetTextColor(White); //文字色——白色
HAL_TIM_Base_Start_IT(&htim4); //开启TIM4的时钟中断——扫描按键
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED); //ADC2初始化校准
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
disp_proc();
led_proc();
key_proc();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
效果图