目录
题目要求:
所用引脚和外设:
根据题意我们可以知道我们用到的外设有:
ADC2:电位器R37
PWM:PA7
LED:PD2……
LCD:
按键:PB0、PB1、PB2
CubeMX配置:
1、基础时钟配置:
SYS:
RCC:
时钟树配置:主频80MHz
2、 ADC2:电位器R37
3、PWM:TIM3->CH2(PA7)
4、LED:
5、按键
软件设计:
主函数编写:
主要思想就是初始化的时候先进行占空比的读取,使频率输出相应占空比,然后在while函数中通过先对电压和占空比进行读取,然后进行按键扫描,最后是显示。下边我会先从基础配置的使用注意到while循环的三个方面进行分析。
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"
#include "lcd.h"
void SystemClock_Config(void);//系统时钟配置函数
int main(void)
{
HAL_Init();//HAL初始化
SystemClock_Config(); //系统时钟配置初始化
KEY_And_LED_Init(); //按键和led灯
ADC2_R37_Init(); //ADC2初始化
TIM3_PA7_Init(); //定时器PWM初始化
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);//打开PWM
LCD_Init(); //LCD 初始化
qujian(); //占空比初始化
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,Du_lcd);//占空比赋值
while (1)
{
qujian(); //电压和占空比函数读取
Key_Scan(); //按键扫描
LCD_Dis(); //LCD显示
}
}
ADC2(电位器R37)的使用注意:
注意:使用的时候先对ADC进行初始化
然后就是ADC的读取,这里我们用到两个函数HAL_ADC_Start()和HAL_ADC_GetValue()
在读取ADC的时候一定要记得先打开ADC,然后在进行读取,具体代码如下。
/* 数据采集 */ uint16_t Get_R37(void) { uint16_t ADC2_Val=0; HAL_ADC_Start(&hadc2); ADC2_Val = HAL_ADC_GetValue(&hadc2); return ADC2_Val; }
这里读取的数据是原始数据,记得转化一下。
PWM(PA7)使用注意:
注意:使用的时候先对定时器3等配置进行初始化,然后打开定时器PWM:HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);。
修改占空比使用:__HAL_TIM_SET_COMPARE();
修改频率使用:
htim3.Init.Period = Fre; HAL_TIM_Base_Init(&htim3);
LED和key注意:
这个其实也没什么要注意的,初始化一下就完事,具体写法参考我之前的文章。
while主循环代码分析:
qujian()函数:该代码主要就是根据题目给提供的占空比和电压的函数图形进行编写的
void qujian(void) { float voltage1; voltage1=(3.3*(Get_R37())/4096);//电压读取 if(voltage1 < 1.0) { Du_lcd=40; } else if(voltage1 <= 2.0 && voltage1>=1.0) { Du_lcd=0.4*(voltage1-1.0)*100+40; } else Du_lcd=80; }
Key_Scan()函数:
void Key_Scan(void) { if(uwTick-uwTick_key_last<50) return ; uwTick_key_last=uwTick; Key_Val=Ked_Read(); Key_Down=Key_Val&(Key_Val_Old^Key_Val); Key_Up=~Key_Val&(Key_Val_Old^Key_Val); Key_Val_Old=Key_Val; Key_control();//按键控制 LED2_Dis();//led2亮灭 }
该函数利用滴答定时器进行定时的按键扫描,Key_control():为按键控制函数,LED2_Dis():为LED2灯的亮灭函数。这两个函数我重点讲解一下,因为这是我感觉在做这套题的时候遇到的一个需要思考的地方。
Key_control()函数
//频率变量 uint16_t Fre_com=1000; uint16_t Fre_swap=999; //占空比变量 uint16_t Du_val=80; //锁 1:解锁:灭 _Bool Lock=1; void Key_control(void) { if(Lock==1) { if(Key_Down==1)//输出引脚频率增加1KHz { Fre_com+=1000; Fre_com_Limit(); Fre_swap=(100000.0/Fre_com)-1; Fre_control(Fre_swap); } if(Key_Down==2)//输入引脚的频率减少1Khz { Fre_com-=1000; Fre_com_Limit(); Fre_swap=(100000.0/Fre_com)-1; Fre_control(Fre_swap); } //Du_val=(Du_lcd/100.0)*Fre_swap;看此句其实和下边一句程序差不多但是这个在刚上电的时候占空比就是0。我感觉应该是数据转化除了问题。换成下边那一句的时候占空比又正常了。 Du_val=(Du_lcd/100.0)*((100000.0/Fre_com)-1); Duty_control(Du_val);//此句和上边一句是用来在程序一开始的时候就保持电压和占空比的函数的显示 } if(Key_Up==3) { Lock=(_Bool)(1-Lock); } if(Lock==0) { Led_dis(0x01); } else { Led_dis(0x00); } }
还有一个注意的点就是在32库中_Bool(布尔类型)的数据类型取反问题。
错误做法:Lock=~Lock;//这样看似没有错误,但是Lock会始终为1,不会正常取反
正确做法:Lock=(_Bool)(1-Lock);
LED2_Dis()函数:这个函数的主要思想其实就是定义一个_Bool类型的变量进行定时取反
_Bool LED2_swap=1; void LED2_Dis(void) { static uint8_t jishi; jishi++; jishi%=3; if(jishi==2) { if((3.3*(Get_R37())/4096)>1.0) { LED2_swap=(_Bool)(1-LED2_swap); if(LED2_swap==1)//led2亮 { if(Lock==0)//当上锁的时候led1也亮 { Led_dis(0x03); } else/当上锁的时候led1不亮 { Led_dis(0x02); } } else if(LED2_swap==0)//led2灭 { if(Lock==0) { Led_dis(0x01);//灭的时候也只是led1在亮 } else { Led_dis(0x00); } } } else { if(Lock==0) { Led_dis(0x01); } else { Led_dis(0x00); } } } }
LCD_Dis()函数
思想和按键一样都是定时扫描
uint32_t uwTick_Lcd_Last; void LCD_Dis(void) { if(uwTick-uwTick_Lcd_Last<200) return ; uwTick_Lcd_Last=uwTick; Dada_Dis(); }
uint8_t Data_str[21]; void Dada_Dis(void) { // LCD_Clear(Black); LCD_SetTextColor(White); LCD_SetBackColor(Black); sprintf((char *)Data_str," "); LCD_DisplayStringLine(Line0,Data_str); sprintf((char *)Data_str," DATA "); LCD_DisplayStringLine(Line1,Data_str); sprintf((char *)Data_str," "); LCD_DisplayStringLine(Line2,Data_str); sprintf((char *)Data_str," Volt:%1.2fV ", voltage);//注意电压 LCD_DisplayStringLine(Line3,Data_str); sprintf((char *)Data_str," "); LCD_DisplayStringLine(Line4,Data_str); sprintf((char *)Data_str," D:%2d%% ", Du_lcd);//占空比 LCD_DisplayStringLine(Line5,Data_str); sprintf((char *)Data_str," "); LCD_DisplayStringLine(Line6,Data_str); sprintf((char *)Data_str," F:%4dHz ", Fre_com);//频率 LCD_DisplayStringLine(Line7,Data_str); sprintf((char *)Data_str," "); LCD_DisplayStringLine(Line8,Data_str); LCD_DisplayStringLine(Line9,Data_str); }