Table of contents
0 topic introduction
The specific requirements are as follows
1 Topic Analysis
At first glance, when you get the topic, it is the basic operation. In practice, a bunch of timer operations are easy to make people dizzy.
First look at the peripherals that need to be used
1. GPIO(key/led)
2.LCD
3. Input capture (TIM3 channel 2) and PWM (TIM2 channel 2)
4.ADC(R37)
First of all, there must be a concept here. When you encounter timing and the like, you should think of the combination of flag bits + counters, use flag bits to trigger timer counting, and separate the initial process from the final execution process to reduce code coupling.
2 Cubemx configuration
The configuration is done as follows:
The clock tree configuration is as follows (make sure SYSCLK=80M)
GPIO configuration (LED setting INPUT initial state high, PD12 enable bit INPUT, KEY setting bit OUTPUT)
The ADC configuration is as follows
Timer 2 TIM2 channel 2 (PWM output configuration PA1) here 80M prescaled by 79 is 1M, and the initial frequency is 1M/(999+1)=1Khz (the title requires 4000, and the specific settings in the following code)
Timer 3 TIM3 channel 2 (input capture output configuration PA7)
Here is a brief introduction: select TI2FP2 as the trigger source (because PA7 is TIM3_CH2), after selecting this, PA7 will turn green, select the internal clock (80M) as the clock, and channel 2 (Channel) as the main channel (PA7 is for channel 2), Channel one acts as a slave channel.
The master channel (channel 2) detects the rising edge, and the slave channel (channel 1) detects the falling edge (the calculation frequency only needs to calculate the capture value of the rising edge, and the calculation duty cycle is calculated according to the proportional relationship between the rising edge and the falling edge).
The prescaler is still 79 (+1) to 1M.
tim2 interrupt is enabled (the only interrupt used in the entire topic)
generate file
Transplant the header files of lcd related files, create a user.c and user.h (personal habit) to put some function codes, the main codes are all written in the main.c file (if the .s file is missing, please add it yourself)
The compiler guarantees that no errors will be reported.
4 codes
There are only two files that I need to write
1. user.c和user.h
2.main.c
The user file is as follows, there is nothing to say about this
user.h:
#include "main.h"
void Led_Disp(unsigned char c);
unsigned char Key_Scan(void);
uint16_t getADC2(void);
user.c:
#include "user.h"
#include "adc.h"
//灯
void Led_Disp(unsigned char c)
{
//全部熄灭
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
//点亮对应位
HAL_GPIO_WritePin(GPIOC, c<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
//按键扫描
unsigned char Key_Scan(void)
{
unsigned char c;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==GPIO_PIN_RESET)
{
c = 1;
}
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==GPIO_PIN_RESET)
{
c = 2;
}
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==GPIO_PIN_RESET)
{
c = 3;
}
else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
{
c = 4;
}
return c;
}
//adc
uint16_t getADC2(void)
{
uint16_t adc = 0;
HAL_ADC_Start(&hadc2);
adc = HAL_ADC_GetValue(&hadc2);
return adc;
}
The main function here uses a counter that executes once in 100ms and a counter that executes once in 50ms. 100ms mainly controls the need for the light to flash, and other timings are placed in the 50ms function.
The function of the timer can be observed according to the test data
timer_b2 is the timer related to button 2, timer_b4 is the timer related to button 4, and timer_MH is the timer that keeps the 2s requirement in the title
flag is the corresponding flag bit, see notes for specific functions
The ninth line of the screen is the adc voltage value and the frequency of cap acquisition
main.c
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"
#include "lcd.h"
#include "user.h"
#include <stdio.h>
void keyPro(void);
void lcdPro(void);
void ledPro(void);
void ADCPro(void);
void timer_100(void);
void timer_50(void);
//tim2 pwm
//tim3 cap
__IO uint32_t uwtick_Key,uwtick_Lcd,uwtick_Led,uwtick_ADC,uwtick_timer_200,uwtick_timer_100,uwtick_timer_50;
//key
unsigned char Key_Value,Key_Old,Key_Up,Key_Dowm;
unsigned char page = 1;
//lcd
unsigned char str[25];
unsigned char test;
//*pwm相关变量
unsigned char PWM_Mode = 0;
unsigned char PWM_p = 0;
float V = 10; //V值
float V_old = 10; //上一次的V值,用于判断V是否稳定
uint16_t CAP1_UP_Count; //上升沿捕获值
uint16_t CAP1_DOWM_Count; //下降沿捕获值
float CAP1_Duty; //捕获占空比
int32_t PWM1_Duty = 10; //PWM输出占空比控制
int32_t PWM1_F = 249; //PWM输出频率控制
unsigned char R = 1; //R
unsigned char K = 1; //K
unsigned char N = 0; //N
float MH = 10; //低频最大值
float ML = 10; //高频最大值
unsigned char select_R_K = 0; //选择R K
unsigned char lock_b4 = 0; //ADC上锁
float adc_value = 0; //ADC值
//timer
int timer_b2 = 0;
int timer_b4 = 0;
int timer_MH = 0;
int timer_ML = 0;
//标志位
unsigned flag_b2 = 0; //1代表正在运行中
int flag_b4 = 0; //0 没有按下 1上升沿 2下降沿
int flag_MHL = 0; //0没超过 1低超过 2高超过
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
LCD_Init();
MX_GPIO_Init();
MX_ADC2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
//cap
HAL_TIM_Base_Start(&htim3);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);
//pwm
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
__HAL_TIM_SET_AUTORELOAD(&htim2,124); //4k=249 8k=124
//__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,124/10);
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
while (1)
{
ADCPro();
lcdPro();
keyPro();
ledPro();
timer_100();//灯闪烁时用
timer_50();
}
}
void lcdPro(void)
{
if(uwTick - uwtick_Lcd<100) return;
uwtick_Lcd = uwTick;
if(page == 1) //数据界面
{
sprintf((char *)str," DATA ");
LCD_DisplayStringLine(Line1,str);
if(PWM_Mode == 0)
{
sprintf((char *)str," M=L ");
}
else
{
sprintf((char *)str," M=H ");
}
PWM_p = PWM1_Duty;
LCD_DisplayStringLine(Line3,str);
sprintf((char *)str," P=%02d%% ",PWM_p);
LCD_DisplayStringLine(Line4,str);
sprintf((char *)str," V=%3.1f ",V);
LCD_DisplayStringLine(Line5,str);
}
else if(page == 2) //参数界面
{
sprintf((char *)str," PARA ");
LCD_DisplayStringLine(Line1,str);
if(select_R_K == 0)
{
LCD_SetTextColor(Green);
}
sprintf((char *)str," R=%d ",R);
LCD_DisplayStringLine(Line3,str);
LCD_SetTextColor(White); //恢复
if(select_R_K == 1)
{
LCD_SetTextColor(Green);
}
sprintf((char *)str," K=%d ",K);
LCD_DisplayStringLine(Line4,str);
LCD_SetTextColor(White); //恢复
}
else if (page == 3) //统计界面
{
sprintf((char *)str," RECD ");
LCD_DisplayStringLine(Line1,str);
sprintf((char *)str," N=%d ",N);
LCD_DisplayStringLine(Line3,str);
sprintf((char *)str," MH=%4.1f ",MH);
LCD_DisplayStringLine(Line4,str);
sprintf((char *)str," ML=%4.1f ",ML);
LCD_DisplayStringLine(Line5,str);
}
//测试用 提交时屏蔽
sprintf((char *)str,"t1:%dt2:%dt3:%dt4:%d ",timer_b2,timer_b4,timer_ML,timer_MH);
LCD_DisplayStringLine(Line7,str);
sprintf((char *)str,"b2:%d b4:%d MHL:%d ",flag_b2,flag_b4,flag_MHL);
LCD_DisplayStringLine(Line8,str);
//adc
sprintf((char *)str, "R37:%4.2fV PWM:%d ",adc_value,1000000/CAP1_UP_Count);
LCD_DisplayStringLine(Line9, str);
}
void keyPro(void)
{
if(uwTick - uwtick_Key<50) return;
uwtick_Key = uwTick;
Key_Value = Key_Scan();
Key_Dowm = Key_Value&(Key_Value^Key_Old);
Key_Up = ~Key_Value&(Key_Value^Key_Old);
if(Key_Value==4&&Key_Old==4&&page==1)
{
flag_b4 = 1;
}
else if(Key_Value!=4&&Key_Old==4&&page==1)
{
flag_b4 = 2;
}
else
{
flag_b4 = 0;
}
Key_Old = Key_Value;
if(Key_Dowm == 1)
{
LCD_Clear(Black);
if(page == 1)
{
page = 2;
}
else if(page == 2)
{
page = 3;
}
else
{
page = 1;
}
}
else if(Key_Dowm == 2)
{
if(page == 1) //数据界面
{
if(flag_b2 == 0)
{
flag_b2 =1;
}
}
if(page == 2) //参数界面
{
if(select_R_K == 0)
{
select_R_K = 1;
}
else
{
select_R_K = 0;
}
}
}
else if(Key_Dowm == 3)
{
if(page == 2)
{
if(select_R_K == 0) //R++
{
R++;
if(R>10)
{
R=1;
}
}
else //K++
{
K++;
if(K>10)
{
K=1;
}
}
}
}
else if(Key_Dowm == 4)
{
if(page == 2)
{
if(select_R_K == 0) //R--
{
R--;
if(R==0)
{
R=10;
}
}
else //K--
{
K--;
if(K==0)
{
K=10;
}
}
}
}
}
//定时相关处理 50ms/次
void timer_50(void)
{
if(uwTick - uwtick_timer_50<50) return;
uwtick_timer_50 = uwTick;
//时间累加
if(flag_b4==1)
{
timer_b4+=50;
}
if(flag_b2 == 1)
{
timer_b2+=50;
if(PWM_Mode ==1)//4000-8000对应249-124 125/5次
{
PWM1_F += 2;
if(PWM1_F>249)
{
PWM1_F = 249;
}
}
else
{
PWM1_F -= 2;
if(PWM1_F<124)
{
PWM1_F=124;
}
}
}
if(flag_MHL == 1)
{
timer_ML+=50;
}
else if(flag_MHL == 2)
{
timer_MH+=50;
}
else
{
timer_ML = 0;
timer_MH = 0;
}
//判断执行
//b4长短按2s
if(flag_b4==2)
{
if(page==1&&timer_b4>2000)//长按
{
if(lock_b4 == 0)
{
lock_b4 = 1;
}
}
else //短按
{
if(page==1&&lock_b4 == 1)
{
lock_b4 = 0;
}
}
}
else if(flag_b4==0)
{
timer_b4 = 0;
}
//b2记时5s PWM高低模式切换
if(flag_b2 == 1&&timer_b2>5000)
{
flag_b2 = 0;
timer_b2 = 0;
N++;
if(PWM_Mode == 0)
{
PWM_Mode = 1;
}
else
{
PWM_Mode = 0;
}
}
//MH2s
if(timer_MH>2000)//低频最大值
{
MH = V;
flag_MHL = 0;
}
else if(timer_ML>2000)
{
ML = V;
flag_MHL = 0;
}
}
unsigned char lednum;
void ledPro(void)
{
if(uwTick - uwtick_Led<100) return;
uwtick_Led = uwTick;
if(page == 1)
{
lednum|=0x1;
}
else
{
lednum&=0xfe;
}
if(lock_b4 == 1)
{
lednum|=0x04;
}
else
{
lednum&=0xfb;
}
Led_Disp(lednum);
}
unsigned char led2flag; //闪烁标志
void timer_100(void)
{
if(uwTick - uwtick_timer_100<100) return;
uwtick_timer_100 = uwTick;
if(timer_b2>0) //闪烁
{
if(led2flag ==0)
{
led2flag = 1;
lednum |=0x2;
}
else if(led2flag == 1)
{
led2flag = 0;
lednum &=0xfd;
}
}
else
{
lednum &=0xfd;
}
}
void ADCPro(void)
{
if(uwTick - uwtick_ADC<150) return;
uwtick_ADC = uwTick;
adc_value = getADC2()*3.3/4096;
//ad转换成占空比
if(lock_b4 ==0)
{
if(adc_value<1.0)
{
PWM1_Duty = 10;
}
else if(adc_value>3.0)
{
PWM1_Duty = 85;
}
else
{
PWM1_Duty = 10+ (adc_value-1)*75/2;
}
}
V = (1000000/CAP1_UP_Count)*2*3.14*R/100/K;
//需要判断V值是否保持
if(V==V_old&&PWM_Mode==0&&V>ML) //低频下
{
flag_MHL = 1;
}
else if(V==V_old&&PWM_Mode==1&&V>MH) //高频下
{
flag_MHL = 2;
}
else
{
flag_MHL = 0;
}
V_old = V;
//频率
__HAL_TIM_SET_AUTORELOAD(&htim2,PWM1_F); //4k
//占空比
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,PWM1_F*PWM1_Duty/100);
}
//中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
CAP1_UP_Count = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2)+1;
CAP1_Duty = (float)CAP1_DOWM_Count/CAP1_UP_Count;
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
CAP1_DOWM_Count = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1)+1;
}
}
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_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();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12;
PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
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 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
5 effect display
Douyin with the same name