使用STM32F103C8T6实现主从机多机串口通信

主要基于stm32f103c8t6完成的一主多从的串口通信开发,关于串口通信的基础内容等站内有很多博主分享,这不在赘述。以下为工程文件的核心代码

主机serial.c

主机串口初始化配置

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>
#include "LED.h"
#include "OLED.h"
#include "Delay.h"

uint8_t Serial_TxPacket[4];				//FF 01 02 03 04 FE
uint8_t Serial_RxPacket[4];
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	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);                                      
     //PA9  TX
    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);             
	//PA10 RX
    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 ;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            
    NVIC_Init(&NVIC_InitStructure);    
  
   //USART 配置
    USART_InitStructure.USART_BaudRate = 9600;
    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);                        

}


void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}


void Serial_SendPacket(void)
{
	Serial_SendByte(0xFF);
	Serial_SendArray(Serial_TxPacket, 4);
	Serial_SendByte(0xFE);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Compare_GetRx(u8 data)
{
	for(uint8_t i=0;i<5;i++)
	{
		if(Serial_RxPacket[i]==data){
			return 1;
		}
	}
	return 0;
}

void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr)
{
    /* Check the parameters */
    assert_param(IS_USART_ALL_PERIPH(USARTx));
   
    //USARTx->DR = (1<<8) | Addr;
    Addr |= (uint16_t)0x0100;
    USARTx->DR = (Addr & (uint16_t)0x010F);
}

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	LED_Init();
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);

		if (RxState == 0)
		{
			if (RxData == 0xFF)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			Serial_RxPacket[pRxPacket] = RxData;
			pRxPacket ++;
			if (pRxPacket >= 4)
			{
				RxState = 2;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == 0xFE)
			{
				RxState = 0;
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

不仅包含串口配置,同时还有数据发送函数、接收数据比较函数等等,接收到的数据以0xff和0xfe作为开头和结尾进行验证,代码主要借鉴江科大自动化up主的代码。

从机Serial.c

从机的串口配置与主机基本类似,只是少了地址发送函数

void USART_SendAddr(USART_TypeDef* USARTx, uint16_t Addr)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
 
//USARTx->DR = (1<<8) | Addr;
Addr |= (uint16_t)0x0100;
USARTx->DR = (Addr & (uint16_t)0x010F);
}

以及设置了从机地址,开启地址唤醒模型等

USART_SetAddress(USART1, 0x01);                    //设置USART1地址
USART_WakeUpConfig(USART1, USART_WakeUp_AddressMark);//地址唤醒
USART_ReceiverWakeUpCmd(USART1,ENABLE);
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>
#include "LED.h"
#include "OLED.h"
#include "Delay.h"

uint8_t Serial_TxPacket[4];				//FF 01 02 03 04 FE
uint8_t Serial_RxPacket[4];
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	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);                                      
     //PA9  TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;         
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;        //复用开漏输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);             
	//PA10 RX
    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 ;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            
    NVIC_Init(&NVIC_InitStructure);    
  
   //USART 配置
    USART_InitStructure.USART_BaudRate = 9600;
    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 Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

void Serial_Printf(char *format, ...)
{
	char String[100];
	va_list arg;
	va_start(arg, format);
	vsprintf(String, format, arg);
	va_end(arg);
	Serial_SendString(String);
}


void Serial_SendPacket(void)
{
	Serial_SendByte(0xFF);
	Serial_SendArray(Serial_TxPacket, 4);
	Serial_SendByte(0xFE);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Compare_GetRx(u8 data)
{
	for(uint8_t i=0;i<5;i++)
	{
		if(Serial_RxPacket[i]==data){
			return 1;
		}
	}
	return 0;
}


void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	LED_Init();
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);

		if (RxState == 0)
		{
			if (RxData == 0xFF)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			Serial_RxPacket[pRxPacket] = RxData;
			pRxPacket ++;
			if (pRxPacket >= 4)
			{
				RxState = 2;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == 0xFE)
			{
				RxState = 0;
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

多余的从机只需要修改 USART_SetAddress(USART1, 0x01); 将0x01更改,其余可以直接复制,需要调用时,只需要在主机的主函数中使用USART_SendAddr(USART1,0x01);便可启动相应地址0x01的从机。
特别注意
从机的TX输出引脚必须配置为开漏输出模式,否则会导致主从机数据收发不正常。

硬件接线

借用了其他博主的图进行的修改,如介意请联系修改。上拉电阻接的VCC为5v
硬件接线

实例验证

采用一主二从的方式进行验证,能够实现目标
接线比较乱,大家凑合着看,主体硬件以上方的图进行接线即可

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32F103C8T6实现主从机多机串口通信

发表评论