器件选择
硬件平台选择STM32F103C8T6最小系统开发板。
STM32代码配置工具使用STM32CubeMX的HAL库进行开发。
光敏模块选择4线光敏电阻传感器模块,(光敏电阻型号5516)。
注1:数据下载使用ST-LINK下载。
注2:串口数据接收使用USB转TTL传输,USB转TTL的TXD接STM32的PA10引脚RXD,RXD接STM32的PA9引脚TXD。
工程案例:
STM32上电后,上位机显示字符串“%%%%%%%Welcome to xiang–ying%%%%%%%”。发送完字符串后,启动系统定时器。上位机通过发送命令读取从ADC通道连接的光敏电阻得到的相应值。发送控制字与返回值如下:
控制字 | 返回信息 |
---|---|
A1 | “XX:XX:XX Sampling value:XXXX ” |
A2 | “XX:XX:XX Voltage value:X.XX ” |
A3 | “XX:XX:XX Sampling value:XXXX Voltage value:X.XX ” |
其他 | “XX:XX:XX Error!!! ” |
定时器相关知识
中等容量的STM32F103增强型系列有7个定时器,包括:1个高级控制定时器、3个普通定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中TIM1挂在APB2总线上,而TIM2-TIM4则挂在APB1总线上。定时器工作时:将时钟信号送入16位可编程预分配器(Prescaler),该预分配器系数为0~65535之间的任意数值。预分配器溢出后,会向16位的主计数器(Counter Period)发出一个脉冲信号。
定时器发生中断时间的计算方法如下:
定时时间=(Presecaler+1)×(1/定时器时钟频率)×(Counter Period+1)
CubeMX定时器配置
CubeMX的基础配置在上一篇文章STM32+光敏模块已经做出了详细介绍,故在此不在叙述,只介绍定时器的相关配置。
对系统的时钟进行如下配置:设置为72MHz,在红色方框中输入后,回车即可。
下面进行定时器的配置,由于定时器在此处仅作定时功能,因此只进行简单的配置即可。将预分配器(Prescaler)设定为7199,主计数器(Counter Period)设定为4999,则定时时间为:(7199/72000000)*4999=0.5S。
其他配置同上篇文章STM32+光敏模块中的配置。
同样配置相关的使能配置
代码主体部分
1、引入头文件,为后续使用变参函数sprintf以及使用清空数组函数memset做准备。
#include "stdio.h"
#include "string.h"
2、变量预先定义。
uint8_t str1[] = "\r\n%%%%%%%Welcome to xiang--ying%%%%%%%";//上电发送字符串
uint8_t h = 0, m = 0, s = 0, ss = 0;//h是时,m是分,s是秒,ss是0.5秒
uint16_t ADC_Sample = 0,ADC_Volt = 0;//DC_Value为采样值,ADC_Volt为电压值
uint8_t str[100];//给定一个数组空间,存放sprintf的内容
uint8_t RX[16];//定义一个数组存放控制字
3、定时器相关函数。回调函数,实现时间功能。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
ss++;
if(ss == 2)//0.5S满2进一
{
ss = 0;
s++;
if(s == 60)//S满60进一
{
s = 0;
m++;
if(m == 60)//m满60进一
{
m = 0;
h++;
}
}
}
}
4、串口通信相关函数。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)//判断是否是串口一
{
switch(RX[0])
{
case 0xa1:
sprintf((char*)str,"\r\n%d:%d:%d Sampling value:%d",h,m,s,ADC_Sample);
break;
case 0xa2:
sprintf((char*)str,"\r\n%d:%d:%d Voltage value:%d.%d%d",h,m,s,ADC_Volt/100,(ADC_Volt/10)%10,ADC_Volt%10);
break;
case 0xa3:
sprintf((char*)str,"\r\n%d:%d:%d Sampling value:%d Voltage value:%d.%d%d",h,m,s,ADC_Sample,ADC_Volt/100,(ADC_Volt/10)%10,ADC_Volt%10);
break;
default:
sprintf((char*)str,"\r\n%d:%d:%d Error!!!",h,m,s);
break;
}
HAL_UART_Transmit(&huart1,str,sizeof(str),10000);//将str里面的内容发送到上位机
HAL_UART_Receive_IT(&huart1,RX,1);//串口接收。
memset(str,0,100);//清空数组内容,为下次存放内容做准备
}
}
5、ADC数据的获取。
void Get_ADC_Sample()
{
HAL_ADC_Start(&hadc1);//打开ADC转换
if(HAL_ADC_PollForConversion(&hadc1,10) == HAL_OK)
{
ADC_Sample = HAL_ADC_GetValue(&hadc1);//将得到的ADC采样值放入变量ADC_Sample中
ADC_Volt = ADC_Sample * 330/4096;//数据转换,电压为3.3V,数据时12位,保留两位小数
}
HAL_ADC_Stop(&hadc1);//停止ADC转换
}
6、主函数中加入下面代码段。
/* USER CODE BEGIN 2 */
HAL_UART_Transmit(&huart1,str1,sizeof(str1),10000);
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
7、在main函数的while循环中加入写入的代码
/* USER CODE BEGIN WHILE */
while (1)
{
Get_ADC_Sample();
HAL_Delay(500);
HAL_UART_Receive_IT(&huart1,RX,1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
结果展示
注:博主是跟随小蜜蜂老师学习,故代码可能与小蜜蜂老师有重复,如侵权,请告知删除。
(2022年05月15日写于郑州)