stm32双机(f1和f4)串口通信发送多字节符号数

  我在网上找串口通信资料的时候,大部分都是上位机和板子间通信,很少看见双机间通信,在这篇文章记录一下自己的思路,希望有所帮助。

接口连线:f103选择串口一,f429选择串口三(地线一定要接!)


f103c8t6发送端

 f103发送端串口配置

void uart_init(u32 bound){
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  //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);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置
	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	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(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 
}

f103串口基本函数

稍微注意一下Usart_SendArrayaa()发送数组这个函数,在这个函数中我们每一次发送的是16位数组数据,在后面的实验中主要调用这个函数

/*****************  发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint16_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}
/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l;
	
	/* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF;
	
	/* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	/* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}
/****************** 发送16位的数组 ************************/
void Usart_SendArrayaa( USART_TypeDef * pUSARTx, uint16_t *array, uint16_t num)
{
  uint8_t i;
	
	for(i=0; i<num; i++)
  {
      Usart_SendHalfWord(pUSARTx, array[i]);
  }
	/* 等待发送完成 */
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}

串口发送数据包,即给数据简单包装,加上帧头0xFF,帧尾0xFE,一次发送一个数据包。发送格式如0xFF 0102 0304 0506 0xFE

void Serial_SendPacket(void)
{
	Usart_SendByte(USART1,0xFF);
	Usart_SendArrayaa(USART1,Serial_TxPacket, 3);
	Usart_SendByte(USART1,0xFE);
	
		/* 等待发送完成 */
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
}

主函数

串口初始化,给数组赋初值,(这只是一个示例,在后续大家自己发送数据的时候可以连续且发送不同的数据),调用发送数据包函数

uint16_t Serial_TxPacket[3];				//定义发送数据包数组,数据包格式:FF 0001 0002 0003 FE
int main(void)
{	
	uart_init(115200);

	while(1)
	{	
	    Serial_TxPacket[0] = 0102;
		Serial_TxPacket[1] = 0304;
		Serial_TxPacket[2] = 0506;
		
		Serial_SendPacket();		//串口发送数据包Serial_TxPacket

	}
}

f429主机接受多个数据

f429串口配置

static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


 /**
  * @brief  DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1 ,中断接收模式
  * @param  无
  * @retval 无
  */
void Debug_USART_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
		
  RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);

  /* 使能 USART 时钟 */
  RCC_APB1PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
  
  /* GPIO初始化 */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  
  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN  ;  
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  
 /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);

  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
  
  /* 配置串DEBUG_USART 模式 */
  /* 波特率设置:DEBUG_USART_BAUDRATE */
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  /* 字长(数据位+校验位):8 */
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  /* 停止位:1个停止位 */
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  /* 校验位选择:不使用校验 */
  USART_InitStructure.USART_Parity = USART_Parity_No;
  /* 硬件流控制:不使用硬件流 */
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  /* USART模式控制:同时使能接收和发送 */
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* 完成USART初始化配置 */
  USART_Init(DEBUG_USART, &USART_InitStructure); 
	
  /* 嵌套向量中断控制器NVIC配置 */
	NVIC_Configuration();
  
	/* 使能串口接收中断 */
	USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
	
  /* 使能串口 */
  USART_Cmd(DEBUG_USART, ENABLE);
}

串口基本接受函数

此函数是标准库stm32f4xx_usart.c中自带的,不需要自己写。注意虽然函数是16位,但是只返回8位数据,因为串口数据寄存器一次只能接受8位数据。

uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  
  /* Receive Data */
  return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
}

串口接受中断函数

接受函数用了状态机的概念,先判断状态是否为0,如果是且数据为0xFF,则跳转到状态1;在状态1处接受并处理数据包中的数据,因为发送端一次只发8位数据,查阅资料发现发送端先发高位,所以在pRxPacket=0时存入数组的是第一位数据的高8位,在pRxPacket=1时存入第一位数据的低8位,此时我们将它合成16位数据,通过高位左移8位,存入数组:Serial_RxPacket[pRxPacket-1] = RxData|(Serial_RxPacket[pRxPacket-1]<<8)。后面2位数据以此类推。此时我们收发多个16位数据已经做到了。还需要解决收发有符号数据。在最开始我定义数据都是无符号数,此时若给数组赋值为负数,收到的值将为0,这是将负数默认为0,而解决的办法就是将定义改为有符号数,并且在状态一中先加入一个循环,在收到高位数据时判断第8位数据是否为1,若是则减1取反(声明我的数据范围没有用到最高位,所以可以借此判断)

void USART3_IRQHandler(void)
{
static uint8_t RxState = 0;		//定义表示当前状态机状态的静态变量
	static uint8_t pRxPacket = 0;	//定义表示当前接收数据位置的静态变量
	if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)		//判断是否是USART1的接收事件触发的中断
	{
		uint16_t RxData = USART_ReceiveData(USART3);				//读取数据寄存器,存放在接收的数据变量
		
		/*使用状态机的思路,依次处理数据包的不同部分*/
		
		/*当前状态为0,接收数据包包头*/
		if (RxState == 0)
		{
			if (RxData == 0xFF)			//如果数据确实是包头
			{
				RxState = 1;			//置下一个状态
				pRxPacket = 0;			//数据包的位置归零
			}
		}
		/*当前状态为1,接收数据包数据*/
		else if (RxState == 1)
		{
			if(pRxPacket%2 == 0)
			{
			if(RxData &(1<<7) != 0)
			{RxData= ~(RxData - 1);
			RxData = -RxData;
			} 
			Serial_RxPacket[pRxPacket] = RxData;	}//将数据存入数据包数组的指定位置
			else 
			Serial_RxPacket[pRxPacket-1] = RxData|(Serial_RxPacket[pRxPacket-1]<<8);
			pRxPacket ++;				//数据包的位置自增
			
			
			if (pRxPacket >= 6)			//如果收够6个数据
			{
				RxState = 2;			//置下一个状态
			}
		}
		/*当前状态为2,接收数据包包尾*/
		else if (RxState == 2)
		{
			if (RxData == 0xFE)			//如果数据确实是包尾部
			{
				RxState = 0;			//状态归0
				Serial_RxFlag = 1;		//接收数据包标志位置1,成功接收一个数据包
			}
		}
		
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);		//清除标志位
	}
}

f429主函数

int main(void)
{	
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  Debug_USART_Config();

  while(1)
	{	
      if (Serial_GetRxFlag() == 1)	//如果接收到数据包
	    	{
						#ifdef USE_LCD_DISPLAY	
					{
						char cStr [ 70 ];		
						sprintf ( cStr, "Gyro        :%8d%8d%8d",Serial_RxPacket[0],Serial_RxPacket[2],Serial_RxPacket[4] );	//角原始数据
						LCD_DisplayStringLine(LINE(8),(uint8_t* )cStr);			
					}
						#endif
			}
	}	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值