文章目录
前言
国赛在即,友友们一起准备国赛吧。
一、题目
功能简述
二、模块初始化以及功能分析
1.模块的初始化
需要使用的模块:LCD、按键B1~B4、TIM2测频率、TIM3输出方波、ADC2双路检测、EEPROM参数存储
2.模块功能分析
LCD–>屏幕显示
按键B1~B4–>按键实现人机交互
TIM2–>测量PLUS1、PLUS2的频率
TIM3–>输出两路不同频率的方波
ADC2–>两路注入通道测量电压值
EEPROM–>参数存储
三、函数实现
1.主函数分析
参数获取:EEPROM检测是否第一次写入,若为第一次写入则默认参数,反则读取存储的参数
/* LCD初始化 */
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
/* iic初始化 */
I2CInit();
/* 开启输入捕获通道 */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
/* 开启输出比较通道 */
HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_2);
/* 参数获取 */
mode = Location = 0;
if(IIC_Read(0x02) != 1)
{
IIC_Write(0x00,1);HAL_Delay(5);
IIC_Write(0x01,1);HAL_Delay(5);
IIC_Write(0x02,1);HAL_Delay(5);
}
Coefficient[0] = IIC_Read(0x00);HAL_Delay(5);
Coefficient[1] = IIC_Read(0x01);HAL_Delay(5);
/* 关闭LED提示 */
GPIOC->ODR |= 0xff00;
GPIOD->ODR |= (1 << 2);
GPIOD->ODR &= ~(1 << 2);
while(1)
/* 屏幕显示以及按键处理 */
Display();
key = KEY_Scan(0);
if(key) KEY_Handle(key);
/* ADC采集以及转换成电压 */
HAL_ADC_Start(&hadc2);
Value[0] = (double)(HAL_ADC_GetValue(&hadc2)&0xfff)/4096*3.3f;
HAL_ADC_Start(&hadc2);
Value[1] = (double)(HAL_ADC_GetValue(&hadc2)&0xfff)/4096*3.3f;
HAL_ADC_Stop(&hadc2);
/* 通过PLUSx的频率计算出输出频率 */
fre1 = (1000000*Coefficient[0])/(2*PWM[0]);
fre2 = (1000000)/(2*PWM[1]*Coefficient[1]);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* LED提示 */
if(mode)
GPIOC->ODR &= ~(1<<8);
else
GPIOC->ODR |= 1<<8;
if(Value[0] > Value[1])
GPIOC->ODR &= ~(1<<15);
else
GPIOC->ODR |= 1<<15;
GPIOC->ODR |= 0x7e00;
GPIOD->ODR |= (1 << 2);
GPIOD->ODR &= ~(1 << 2);
2.子函数分析
1.void Display(void)
mode为0,屏幕显示1,反之显示2.
void Display(void)
{
if(!mode)
{
sprintf((char *)str," Measure ");
LCD_DisplayStringLine(Line0,str);
if(PWM[0] > 1000)
sprintf((char *)str," PLUS1:%2dkHz",(uint16_t)PWM[0]/1000);
else
sprintf((char *)str," PLUS1:%3dHz",(uint16_t)PWM[0]);
LCD_DisplayStringLine(Line2,str);
if(PWM[1] > 1000)
sprintf((char *)str," PLUS2:%2dkHz",(uint16_t)PWM[1]/1000);
else
sprintf((char *)str," PLUS2:%3dHz",(uint16_t)PWM[1]);
LCD_DisplayStringLine(Line4,str);
sprintf((char *)str," AO1: %.2lfV",Value[0]);
LCD_DisplayStringLine(Line6,str);
sprintf((char *)str," AO2: %.2lfV 1",Value[1]);
LCD_DisplayStringLine(Line8,str);
}
else if(mode == 1)
{
sprintf((char *)str," Setup ");
LCD_DisplayStringLine(Line0,str);
if(Location == 0)
LCD_SetTextColor(Green);
sprintf((char *)str," DIV: %d",Coefficient[0]);
LCD_DisplayStringLine(Line4,str);
LCD_SetTextColor(White);
if(Location == 1)
LCD_SetTextColor(Green);
sprintf((char *)str," MUL: %d",Coefficient[1]);
LCD_DisplayStringLine(Line6,str);
LCD_SetTextColor(White);
sprintf((char *)str," 2");
LCD_DisplayStringLine(Line8,str);
}
}
2.uint8_t KEY_Scan(void)
按键识别
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t flag=1;
if(mode) flag = 1;
if(flag &&(KEY_B1 == 0 || KEY_B2 == 0 || KEY_B3 == 0 || KEY_B4== 0 ))
{
HAL_Delay(10);
flag = 0;
if (KEY_B1 == 0) return B1_Press;
else if (KEY_B2 == 0) return B2_Press;
else if (KEY_B3 == 0) return B3_Press;
else if (KEY_B4 == 0) return B4_Press;
}else if(KEY_B1 == KEY_B2 == KEY_B3 == KEY_B4 == 1) flag = 1;
return 0;
}
3.void KEY_Handle(uint8_t key)
根据按键的功能,分别对其进行编写
Location表示对某一参数进行修改
void KEY_Handle(uint8_t key)
{
if(key == B1_Press)
{
mode = !mode;
LCD_Clear(Black);
HAL_TIM_OC_Stop_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_OC_Stop_IT(&htim3, TIM_CHANNEL_2);
if(!mode)
{
EEPROM_Conserve();
HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_1);
HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_2);
}
}
else if(key == B2_Press)
{
Location++;
Location %= 2;
}
else if(key == B3_Press && mode == 1)
{
if(Coefficient[Location] < 4)
Coefficient[Location]++;
}
else if(key == B4_Press && mode == 1)
{
if(Coefficient[Location] > 1)
Coefficient[Location]--;
}
}
4.EEPROM读写函数
根据时许编写
void IIC_Write(uint8_t address, uint8_t data)
{
I2CStart();
I2CSendByte(0xA0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
uint8_t IIC_Read(uint8_t address)
{
uint16_t data;
I2CStart();
I2CSendByte(0xA0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xA1);
I2CWaitAck();
data = I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return data;
}
5.void EEPROM_Conserve(void)
对分频系数和倍频系数进行存储
void EEPROM_Conserve(void)
{
IIC_Write(0x00, Coefficient[0]);HAL_Delay(5);
IIC_Write(0x01, Coefficient[1]);HAL_Delay(5);
}
6.void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
两路输入捕获,得到PLUS1、PLUS2的频率PWM[0]、PWM[1]
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim2)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(Value2 < TIM2->CCR2)
Value2 = TIM2->CCR2 - Value2;
else
Value2 = 0xffff+TIM2->CCR2 - Value2;
PWM[0] = 1000000 / Value2;
Value2 = TIM2->CCR2;
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
if(Value3 < TIM2->CCR3)
Value3 = TIM2->CCR3 - Value3;
else
Value3 = 0xffff+TIM2->CCR3 - Value3;
PWM[1] = 1000000 / Value3;
Value3 = TIM2->CCR3;
}
}
}
7.HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
不同频率的双通道输出分频方波和倍频方波
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim3)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
TIM3->CCR1 += fre1;
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
TIM3->CCR2 += fre2;
}
}
}
测试:
总结
以上代码全是个人思路(除仿照按键设别),如果觉得不错请支持一下。
在此声明一下,本人是提供一些思路,所以直接放c文件、h文件就没有意义。
分段解析更通俗易懂,所以请多理解,不喜勿喷,谢谢。