|
最近在做多节点无线通信,用到STM32 USART多机串行通信。 记录下多机串行通信配置要点。 下面是我封装的会用到的函数: - // .h
- #ifndef _MULTIUSART_H
- #define _MULTIUSART_H
- #include "sys.h"
- #include "stm32f10x_usart.h"
- /*
- USART_SR状态寄存器
- USART_DR数据寄存器
- USART_BRR波特率寄存器
-
- TXD-PA9
- RXD-PA10
- */
- #define USART_REC_LEN 60
- #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
-
- extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
- extern u16 USART_RX_STA; //接收状态标记
- extern void USART_InitEx(u32 bound);
- extern void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data);
- extern void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr);
- #endif
复制代码- // .c
- #include "MultiUSART.h"
- //串口1中断服务程序
- //注意,读取USARTx->SR能避免莫名其妙的错误
- u8 USART_RX_BUF[USART_REC_LEN] = ""; //接收缓冲,最大USART_REC_LEN个字节.
- //接收状态
- //bit15, 接收完成标志
- //bit14, 接收到0x0d
- //bit13~0, 接收到的有效字节数目
- u16 USART_RX_STA=0; //接收状态标记
- void USART_InitEx(u32 bound)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
- USART_DeInit(USART1); //复位串口1
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- //Usart1 NVIC 配置
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
- NVIC_Init(&NVIC_InitStructure);
-
- //USART 初始化设置
- USART_InitStructure.USART_BaudRate = bound;
- USART_InitStructure.USART_WordLength = USART_WordLength_9b;
- 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(USART1, &USART_InitStructure); //初始化串口
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启中断 接收中断
- USART_Cmd(USART1, ENABLE); //使能串口
-
-
- USART_SetAddress(USART1, 0x01); //设置USART1节点地址
- //USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark);//地址标记唤醒
-
- //USART_ReceiverWakeUpCmd(USART1,ENABLE);
- }
- void USART_SendDataEx(USART_TypeDef* USARTx, uint16_t Data)
- {
- /* Check the parameters */
- assert_param(IS_USART_ALL_PERIPH(USARTx));
- assert_param(IS_USART_DATA(Data));
-
- /* Transmit Data */
- USARTx->DR = (Data & (uint16_t)0x01FF);
-
- //等待发送缓冲区空
- //或 等待发送结束
- //while((USART1->SR&0X40)==0);
- while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){};
- }
- void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr)
- {
- /* Check the parameters */
- assert_param(IS_USART_ALL_PERIPH(USARTx));
-
- // 9位字长, 最高位为1,低四位为地址
- //USARTx->DR = (1<<8) | Addr;
- Addr |= (uint16_t)0x0100;
- USARTx->DR = (Addr & (uint16_t)0x010F);
- }
- #if EN_USART1_RX
- void USART1_IRQHandler(void) //串口1中断服务程序
- {
- u8 Res;
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
- {
- Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
-
- if((USART_RX_STA&0x8000)==0) //接收未完成
- {
- if(USART_RX_STA&0x4000) //接收到了0x0d
- {
- if(Res!=0x0a)
- USART_RX_STA=0; //接收错误,重新开始
- else
- USART_RX_STA|=0x8000; //接收完成了
- }
- else //还没收到0X0D
- {
- if(Res==0x0d)
- USART_RX_STA|=0x4000;
- else
- {
- USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;
- USART_RX_STA++;
- if(USART_RX_STA>(USART_REC_LEN-1))
- USART_RX_STA=0; //接收数据错误,重新开始接收
- }
- }
- }
- }
- }
- #endif
复制代码在主机端,可以写个键盘控制发送地址,类似: switch(KeyValue)
{
case 1: USART_SendAddr(USART1, 0x01); break; //从机1
case 2: USART_SendAddr(USART1, 0x02); break; //从机2 ............. 然后即可自己设定通信协议分别处理从机发过来的数据了。
在从机端,由于要设为静默模式: USART_SetAddress(USART1, 0x01); //设置USART1节点地址 如从机1设为0x01 USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark); //地址标记唤醒 USART_ReceiverWakeUpCmd(USART1,ENABLE); //使处于静默模式 这几句在串口初始化时要开启。
当主机发出正确地址给从机时,下面if 语句便成立可执行。 //从机被唤醒, 接收中断恢复正常 if((USART1->CR1 &((uint16_t)0x0002)) == 0)
{........} 从而可在其中添加从机要给主机发送数据的程序。
|