PM2.5传感器模块,UART输出,使用USART3。
正极接P10的VCC3.3,负极接P10的GND,TXD接Z1的16脚US3_RX(70),注意:正常的话正极是接VCC5,但是我接上VCC5后,模块上的稳压二极管烧了,然后我将稳压二极管卸掉后使用VCC3.3供电,数据发送正常。
(1)波特率9600,数据位8位,停止位1位,校验位无。
(2)通信方式:传感器通过US3_RX返回浓度数据,串口上报通讯周期:1+0.5 秒。
(3)数据格式:10位数据:报文头(0xAA) 指令号(0xC0) 数据1(PM2.5低字节) 数据2(PM2.5高字节) 数据3(PM10低字节) 数据4(PM10高字节) 数据5(0,保留) 数据6(0,保留) 校验位 报文尾(AB)。
(4)校验和计算:数据1 到数据6 的字节加和。
(5)气体浓度值计算
PM2.5 数据内容:PM2.5(ug/m3) = ((PM2.5 高字节*256) + PM2.5 低字节)/10
PM10 数据内容:PM10(ug/m3) = ((PM10 高字节*256) + PM10 低字节)/10
(6)区分APB1和APB2
时钟输出中有很多是带使能控制的,如AHB总线时钟、内核时钟、各种APB1外设、APB2外设等。当需要使用某模块时,必需先使能对应的时钟。
连接在APB1(低速外设)上的设备:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、 Timer2、Timer3、Timer4。
连接在APB2(高速外设)上的设备:GPIO_A-E、USART1、ADC1、ADC2、ADC3、TIM1、TIM8、SPI1、AFIO。
参考:STM32的时钟树深入详解
(7)起初未弄清APB1和APB2的概念,在开启USART3和GPIOB的时钟时,错误写成:
RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART3|RCC_APB2Periph_GPIOB, ENABLE); //使能USART3,GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART3|RCC_APB2Periph_GPIOB, ENABLE); //使能USART3,GPIOB时钟
USART3应该用RCC_APB1PeriphClockCmd使能时钟,GPIOB应该用RCC_APB2PeriphClockCmd使能时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
(8)代码分析
<1>初始化uart3
//初始化IO 串口3
//bound:波特率
void uart3_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//APB2改为APB1,因为USART3是连接到APB1(低速外设)上的设备
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //??USART2,GPIOA??
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //??USART2,GPIOA?? USART_DeInit(USART3); //复位串口3
//USART1_TX PB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
//USART1_RX PB.11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART3, &USART_InitStructure); //初始化串口
//Usart3 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART3, ENABLE); //使能串口
}
<2>串口3中断处理函数,更新PM2.5浓度数据PM25Data
//PM2.5传感器上传数据时就会触发串口3中断
void USART3_IRQHandler(void) //串口3中断服务程序
{
//串口收到的10位数据:报文头(0xAA) 指令号(0xC0) 数据1(PM2.5低字节) 数据2(PM2.5高字节) 数据3(PM10低字节) 数据4(PM10高字节) 数据5(0,保留) 数据6(0,保留) 校验位 报文尾(AB)
u8 checksum = 0;//校验和
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断
{
//(USART1->DR); //读取接收到的数据
USART_RX_BUF_3[USART3Count++] = USART_ReceiveData(USART3);//读取10字节到USART_RX_BUF_3
if(USART3Count == 10)
USART3Count = 0;//当接收到第10个字符后,从数组USART_RX_BUF_3的开头开始写
checksum = USART_RX_BUF_3[2] + USART_RX_BUF_3[3] + USART_RX_BUF_3[4]
+ USART_RX_BUF_3[5] + USART_RX_BUF_3[6] + USART_RX_BUF_3[7];//校验和
if(checksum == USART_RX_BUF_3[8])//证明接收到的数据是正确的
PM25Data = (USART_RX_BUF_3[3] * 256 + USART_RX_BUF_3[2]) / (float)10;
}
}
<3>串口显示PM25浓度:
/*****************************************串口显示PM2.5浓度*****************************************/
printf("USART_RX_BUF_3:");//输出接收数据以比对
for(PM25DataCount = 0;PM25DataCount< 10;PM25DataCount++)
printf("%x ",USART_RX_BUF_3[PM25DataCount]);
printf("\r\n");
printf("PM2.5浓度为:%0.1fug/m3\r\n",PM25Data);//PM25Data通过串口3中断程序USART3_IRQHandler更新
代码地址
有需要请加QQ:1447491726,进行详细的技术交流,共同进步。