利用HAL库构建的温度报警系统Protues仿真详解
基于HAL库的温度报警系统 Protues仿真
一、新建Protues工程
新建工程看这个新建Protues工程教程就好啦。
二、原理图设计
用Protues仿真相比于上板非常让人头疼的一点就是,只有一个核心而很多常见的外围电路设计都没了,然后找了半天都不知道哪里错了,结果是一些基础外部电路设计的问题。
本工程使用的是STM32F401RE,具体外围电路的搭建如下:
整体电路是F401、温度传感器、串口、LCD1602和电机驱动电路构成。
下面说一下需要注意的一些细节:
1.ADC的参考电平和复位引脚
这里要注意F401的ADC的参考电压VREF是需要自行连接的。之前我也用过F103R6做过一模一样的项目但是当时并做这样的没有处理,应该是不同的设计有些区别吧。
这里还要把NRST接VDD,NRST是MCU的复位引脚,如果不接VDD而让它浮空的话就会出现奇奇怪怪的问题。
2.串口引脚与COMPIN的连接方式
注意这里单片机串口引脚的RX要和COMPIN的RX连接,同样的TX连接TX。
3.LCD1602的供电与偏光调节
这里主要是VEE这个液晶偏光的调节引脚,一般是要接个滑动变阻器进行分压的,这里就简化成这样了(太懒了不想改嘿嘿嘿)。
三、新建CubeMX工程
1.时钟配置
进行Protues仿真的时候一定要用HSI!!!
进行Protues仿真的时候一定要用HSI!!!
进行Protues仿真的时候一定要用HSI!!!
哪怕是你把输入到总线上的时钟调整和HSI一样大小也不可以
其实,我也不知道为什么不可以,但是实践出真知呜呜呜(′~`;)
2.ADC
因为只是单纯采个电平这里就用ADC直流采样就好了,把IN1勾选上什么都不用改啦啦啦
3.串口
串口这里需要注意的是波特率等参数的设置,需要和后面虚拟串口等一致。
虽然作业要求是要做串口收发,但是这里如果想偷懒的话连串口中断都可以不开后面直接调用串口接收函数就好了。
如果想用串口中断的话到下面这个地方勾选上就好了
4.GPIO
引脚图配置如下:
GPIO这里主要是为LCD1602分配引脚,注意这里的PC0-PC7要全部设置为GPIO_Output作为LCD1602中D0-D7的输出。
原因是PC0-PC7是对应到一个ODR寄存器的,而很多可移植的LCD1602的代码都是通过操作寄存器来实现数据写入的。
四、虚拟串口配置
这部分建议直接去看虚拟串口工具VSPD的安装和使用这个视频,讲得非常详细啦。
五、程序设计
这里说一下几个主要功能的程序设计
1.串口重定向
首先点击魔术棒,勾选如下选项:
然后,将printf需要的头文件引入:
最后,将如下代码添加到工程中:
int fputc(int ch,FILE *f) //串口重定向
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY);
return ch;
}
到这里就可以通过调用printf实现串口发送啦。
2.串口接收
前面说了接收有两种方式,一种是轮询,一种是中断。
(1)轮循实现串口接收
轮询只需要在while里面调用如下函数即可:
HAL_UART_Receive(&huart1, (uint8_t *)&aRxBuffer, 1,100);
其中&aRxBuffer表示的串口接收到数据后存储的变量地址,1表示数据长度为1,100为等待响应时间,也可以设置为HAL_MAX_DELAY。
由于作业要求发送和接收的内容都是固定的,这里用轮询也没有什么关系。但是考虑到整个系统的灵活性和不定长接收相关的问题还是用串口中断比较好。
(2)中断实现串口接收
串口中断的代码其实也很固定,具体分一以下几个部分:
首先就是定义串口接收中断的相关变量。这里aRxBuffer是用于存储每次串口接收中断接收到的一个字符,然后将每次接收到的aRxBuffer存入RxBuffer数组当中。
#define RXBUFFERSIZE 256 //串口接收
char RxBuffer[RXBUFFERSIZE]={0};
char aRxBuffer; //接收中断缓冲
uint8_t Rx_Cnt = 0; //接收缓冲计数
注意!!注意!!不要忘了在初始化后开启串口接收中断!!
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
这个就是串口接收中断的回调函数,可以看到HAL_UART_Receive_IT开启了串口接收中断后将接收到的字符存储到aRxBuffer的地址下,并且每次都将接收到的字符存入RxBuffer数组当中。
由于串口接收中断每次执行后会自动清楚相关的标志位,所以一定要在回调函数的最后重新开启中断!!
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_IRQHandler(&huart1);
if(huart->Instance == USART1){
RxBuffer[Rx_Cnt++]=aRxBuffer;
HAL_StatusTypeDef return_state;
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
}
}
当然,串口需要接收好多次不同的数据,所以还需要一个函数来清空RxBuffer数组。
//清空串口接收缓冲区
void RX_Buffer_Clear(void){
for(int i=0;i<RXBUFFERSIZE; i++){
RxBuffer[i]=0;
Rx_Cnt=0;
}
}
3.ADC直流采集
通过查阅资料之后发现F4的ADC好像并没有校准操作,直接开启就可以进行直流采集了,具体代码如下:
HAL_ADC_Start(&hadc1); //启动ADC转换
if(HAL_ADC_PollForConversion(&hadc1,50) == HAL_OK){}
ADC_Value = HAL_ADC_GetValue(&hadc1); //获取ADC的值,结果存放在ADC_Value里面
注意,由于F401为12位ADC,得到值范围在0到4095之间,根据电压和温度转换关系,还需要加入下面这句:
V=ADC_Value*500/4096;
4.LCD1602
LCD1602开源的代码很多这里也不赘述,其实移植的话就是修改IO,LCD1602的具体介绍和相关驱动代码可以去看这篇博客。
六、联调仿真
最终仿真结果如下图所示
作者:コナソ(°ー°〃)