相关电路与IO引脚
注意:串口打印重定向后使用printf打印需要在keil里勾选 Use MicroLIB ,否则会卡住。
参看:https://zhuanlan.zhihu.com/p/565613666
串口重定向:
/* USER CODE BEGIN Includes */
#include <stdio.h>// 包含标准输入输出头文件
/* USER CODE END Includes */
int fputc(int ch,FILE *f)
{
//采用轮询方式发送1字节数据,超时时间设置为无限等待
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch=0;
// 采用轮询方式接收 1字节数据,超时时间设置为无限等待
HAL_UART_Receive( &huart1,(uint8_t*)&ch,1, HAL_MAX_DELAY );
return ch;
}
ADC的GPIO复用引脚表:
参考:
视频教程:14.1和14.2节
【【14.1】STM32 ADC模数转换器 感知世界的钥匙——Kevin带你读《STM32Cube高效开发教程基础篇》】 https://www.bilibili.com/video/BV1CV4y1k71M/?share_source=copy_web&vd_source=9332b8fc5ea8d349a54c3989f6189fd3
博客:
https://blog.csdn.net/little_grapes/article/details/121154513
ADC相关函数:
实验内容
1、利用 ADC1 通道 3 采样 PA3 的电压值,将 ADC 采样值和转换的电压值通过串行口返回, 调节电位器,观察运行结果。
根据前面的复用引脚表,选择ADC1的通道IN3。
CubeMX配置如下,
采样时间(sampling time)选择55.5cycles,采样时间长一些结果更准确。
因为也要使用中断方式,所以要开启中断
轮询方式:
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//轮询
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,50);//is it finished?
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1),HAL_ADC_STATE_REG_EOC))
{
adc_res=HAL_ADC_GetValue(&hadc1);
printf("voltage value:%.1f V\r\n",adc_res*3.3/4095);
}
//延时一段时间再启动转换
HAL_Delay(1000);
}
/* USER CODE END 3 */
中断方式(直接把轮询相关的代码替换,详见参考的文章)
/* USER CODE BEGIN 2 */
//中断方式启动ADC转换
HAL_ADC_Start_IT(&hadc1);
/* USER CODE END 2 */
回调函数:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance==ADC1){
adc_res=HAL_ADC_GetValue(&hadc1);
printf("voltage value:%.2f V,original value:%d \r\n",adc_res*3.3/4095,adc_res);
}
}
2、编写程序,利用光敏电阻设计光电开关,控制 LED1 点亮和熄灭。
光敏电阻对应引脚PA2,选择ADC1的IN2通道,选择使用定时器作为中断源,注意此时要关闭连续转换,cubemx配置:
记得开启ADC中断。
然后配置定时器,这里用定时器3,频率为72mhz/(7200*5000)
代码:
/* USER CODE BEGIN 2 */
//中断方式启动ADC转换
HAL_ADC_Start_IT(&hadc1);
//开启定时器3
HAL_TIM_Base_Start(&htim3);
/* USER CODE END 2 */
回调函数(这里设置设置计算电压的方法也是按照3.3V作为参考电压,大于2.1V就点亮灯(这里点亮了两个灯),灯的引脚看前面的GPIO实验)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance==ADC1){
adc_res=HAL_ADC_GetValue(&hadc1);
// printf("voltage value:%.1f V\r\n",adc_res*3.3/4095);
if(adc_res*3.3/4095>2.1){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,0);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,1);
} else{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,1);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,0);
}
}
}
3、设计一个室内温控系统,PA3 采样电压表示采集的温度,阈值上限为 2.5V,下限为 1V,采样电压显示在数码管上。
(1)当采样电压低于 1V(温度过低),蜂鸣器鸣叫(模拟声音报警),LED1 闪烁(模 拟光报警),全彩灯打开(模拟加热)。
(2)当采样电压位于 1V~2.5V 时,正常,蜂鸣器不叫,发光二极管不亮,电机不转。
(3)当采样电压高于 2.5V 时(温度过高),蜂鸣器鸣叫(模拟声音报警),LED1 闪烁 (模拟光报警),电机旋转(模拟风扇降温)。
这里蜂鸣器(PB8)用定时器4通道3输出一定频率的PWM控制,led闪烁间隔时间用cnt控制,循环了一定次数才翻转电平。配置如下:
段码表10以后是原来的数字加上了小数点显示
/* USER CODE BEGIN 0 */
uint8_t flag=0;
int res=0;
//uint8_t table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x80 };//10表示'-'
uint8_t table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x80+0x3f,0x80+0x06,0x80+0x5b,0x80+0x4f,0x80+0x66,0x80+0x6d,0x80+0x7d,0x80+0x07,
0x80+0x7f,0x80+0x6f, };//10表示'-'
uint8_t s[]={0,0,0,0,0,0,10,0};
uint16_t adc_res=0;
int light_flag=0;
uint8_t n1;
uint8_t n2;
void write_byte(uint8_t date){
unsigned char i;
for(i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,(date>>(7-i))&0x01);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,0);
}
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,0);
}
int fputc(int ch,FILE *f)
{
//采用轮询方式发鿿1字节数据,超时时间设置为无限等待
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch=0;
// 采用轮询方式接收 1字节数据,超时时间设置为无限等待
HAL_UART_Receive( &huart1,(uint8_t*)&ch,1, HAL_MAX_DELAY );
return ch;
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance==ADC1){
adc_res=HAL_ADC_GetValue(&hadc1);
float vol=adc_res*3.3/4095;
printf("voltage value:%.2f V\r\n",vol);
if(vol <1){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,0);
light_flag=1;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, 0);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, 0);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
} else if(adc_res*3.3/4095 >=1 &&adc_res*3.3/4095<=2.5){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,1);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, 0);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, 0);
HAL_TIM_PWM_Stop(&htim4,TIM_CHANNEL_3);
light_flag=0;
}else{
light_flag=1;
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, 1);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, 0);
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
}
n1=(uint8_t)vol;
n2=(uint8_t)(vol*10)%10;
//printf(" value:%d V\r\n",n1);
//printf(" value:%d V\r\n",n2);
}
}
int cnt=0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(light_flag==1){
cnt++;
if(cnt==50){
cnt=0;
HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_0);
}
}else{
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,0);
cnt=0;
}
s[7]=n2;
s[6]=n1+10;
for(int i=8;i<11;i++){
write_byte(table[s[15-i]]);
HAL_GPIO_WritePin(GPIOF,0x01<<i,0);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOF,0x01<<i,1);
}
}
/* USER CODE END 3 */
源文件见个人主页。