5、串口通信

 一、STM32F1串口资源(5个串口-3个同步,2个异步)

串口号发送(TX)接收(RX)
USART1PA9PA10
USART2PA2PA3
USART3PB10PB11
UART4PC10PC11
UART5PC12PD2

二、异步串口通信数据构成:

起始位-0+数据位(8bit)+[奇偶校验位(第9bit)]+停止位-1(1/1.5/2bit)

什么是奇偶校验:

奇校验:8个数据位,加起来如果是偶数个1,则第9位自动补1;加起来如果是奇数个1,则第9位就自动补0;目的就是最终:使数据有奇数个1。

偶校验:同理。目的是最终:使数据有偶数个1。

三、框图分析(不太会分析,先看个大概吧)

四、波特率的计算:

                         Baud= \frac{Fpclk}{16*USARTDIV}

                         USARTDIV=整数部分+小数部分

                         整数部分=DIV_Mantissa;小数部分=(DIV_Fraction/16)

以串口1为例:USART1的时钟,使用的是APB2总线上的PCLK2(默认72M)

要将波特率设置为115200,则:Baud=115200

三个未知数,还剩下USARTDIV=Fpclk/(Baud*16)=72M/(115200*16)≈39.0625

USARTDIV = 39+0.0625

整数部分39,直接写入:DIV_Mantissa=39=0x27

小数部分0.0625,0.0625=(DIV_Fraction/16):DIV_Fraction=1=0x01

通过查阅寄存器,小数部分占了4bit,整数部分占12bit;因此,要设置波特率为115200,需要向寄存器写入:USART1_BRR=0x0271

五、库函数应用

串口配置步骤:

1、串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();

2、串口复位:USART_DeInit();

3、GPIO端口模式设置:GPIO_Init();

发送(PA9):推挽输出

接收(PA10):上拉输入 或 浮空输入

4、串口参数初始化:USART_Init();

5、开中断,并初始化NVIC:NVIC_Init(); & USART_ITConfig();

6、使能串口:USART_Cmd();

7、编写中断处理函数:USARTx——IRQHandler();

8、串口数据收发:USART_SendData(); & USART_RceviceData();

9、串口传输状态获取:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);

ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

--------------------------------------------------------------------------------------------------------------------------

根据时钟树可以知道:USART1是挂载在APB2下,因此:从stm32f10x_rcc.h找到:

RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

//如果不知道填哪些参数,可以F12进入函数的定义,进入到参数有效性检查中查看可填参数列表

void Usart1_Config(void)
{
	USART_InitTypeDef USART1_nitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	USART_DeInit(USART1);
	Usart1_GPIO_Config();
	Usart1_NVIC_Config();
	USART1_nitStructure.USART_BaudRate=115200;
	USART1_nitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART1_nitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART1_nitStructure.USART_Parity=USART_Parity_No;
	USART1_nitStructure.USART_StopBits=USART_StopBits_1;
	USART1_nitStructure.USART_WordLength=USART_WordLength_8b;
	USART_Init(USART1,&USART1_nitStructure);
	USART_Cmd(USART1,ENABLE);

}

void Usart1_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
}

如果使用中断,则还需要配置优先级:misc.c中:

NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)//优先级分组//为了避免冲突,只分组一次,一般放到main函数中。

void Usart1_NVIC_Config(void)
{
	NVIC_InitTypeDef USART1_NVIC_InitStructure;
	
	USART1_NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	USART1_NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=15;
	USART1_NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	USART1_NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
	NVIC_Init(&USART1_NVIC_InitStructure);
}

 中断处理函数(函数名一定要写对!!!)

/**
  * @brief  This function handles Usart1 interrupt request.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		USART_SendData(USART1,USART_ReceiveData(USART1));
	
	}
	
}

/************************************中断接收优化******************************************************/

/**
  * @brief  This function handles Usart1 interrupt request.
  * @param  None
  * @retval None
  */
	
void USART1_IRQHandler(void)
{
	u8 temp_Rx_Data = 0;
	
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == 1 )  //判断接收到的中断,是否为接收中断
	{
		temp_Rx_Data=USART_ReceiveData(USART1);//读出RD寄存器数据
		if((USART1_RX_State & (1<<15)) == 0) //判断是否接收未接收完成(0A)
		{
			if((USART1_RX_State & (1<<14)) == (1<<14))//判断上一个数据是否为0x0D
			{
				if(temp_Rx_Data != 0x0A)//接收数据不是0D 0A
				{
					USART1_RX_State=0;//清空标记和计数重新接收
				}
				else
				{
					USART1_RX_State |= (1<<15);//接收完成标记
				}
			}
			else//未收到0x0D
			{
				if(temp_Rx_Data == 0x0D)
				{
					USART1_RX_State |= (1<<14);//标记接收到0x0D
				}
				else//存数据
				{
					USART1_Rx_Data[USART1_RX_State & 0x3fff]=temp_Rx_Data;//保存数据(只用了0--13bit)
					//由于接收数据时候,不会遇到标志位,置位标志位之后也不应该有数据,所以可以清0
					USART1_RX_State++;//计数+1
					if(USART1_RX_State >= UART1_Rx_LEN-1)//0-199//数据超了,重新接收
					{
						USART1_RX_State=0;
					}
				}
			}
		} 
	}
	else
	{
		//主函数还未处理上次数据,不接收新数据
	}
	
}

参考原子写的,有点绕,自己慢慢分析吧,来不及分析了。我要修改前面写的用systick写delay做延时的内容去了。(写的太恶心了)

int main(void)
{	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);	
	SysTick_Config(SystemCoreClock/1000);
	LED_GPIO_Config();
	Usart1_Config(115200);
	

	while(1)
	{
		
		if(SysTickTime>=1000)
		{
			GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)?
			GPIO_ResetBits(GPIOC, GPIO_Pin_13),
			SysTickTime=0: 
			GPIO_SetBits(GPIOC, GPIO_Pin_13),
			SysTickTime=0;
		}
		if(USART1_RX_State & (1<<15))//接收到一组数据
		{
			len = (USART1_RX_State & 0x3fff);//从13位数据中获取数据长度
			for(u16 n=0;n<len;n++)
			{
				USART_SendData(USART1,USART1_Rx_Data[n]);
				while((USART_GetFlagStatus(USART1,USART_FLAG_TC)) == 0);//一帧数据发送结束判断TC位
			}
			printf("\r\n");
			USART1_RX_State=0;
		}
	}
}

用printf函数,需要增加一个函数重映射,否则用不了

//重定义fputc函数
int fputc(int ch,FILE *f)
{
	while((USART1->SR&0x40) == 0);
	USART1->DR = (u8)ch;
	return ch;
}

 自己写的串口发送函数:

1、发送任意长度的字符串

char Data[]="12345678\r\n";

void SendData_char(char *p,u8 n)
{
	printf("n=%d\r\n",n);
	for(;n>0;n--)//sizeof,求字符串长度,带了'\0'
	{
		USART1->DR = (u8) (*p & 0xFF);
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
		p++;
	}
}

 2、发送32位十六进制数据(有待完善。。。)

void SendData_int32(u32 data)
{
	int i=3;
	do
	{
		USART1->DR = (u8) ((data & 0xFF000000) >> 24);
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
		data = data << 8;
	}
	while(i--);
}


SendData_int32(0x12345678);

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值