江科大32开发板USART串口发送教程

 1.程序初始化流程

1)开启USART和GPIO时钟。

2)GPIO初始化,把TX配置成复用输出,RX配置成输入。

3)使用结构体配置USART。

如果只需发送功能,直接开启USART就行了。

如果需要发送和接收,需要在开启USART之前加上ITConfig和NVIC的代码。

初始化完成,只需调用特定函数就能完成发送和接收。要获取发送和接收的状态,调用获取标志位函数。

2.USART常用函数

void USART_DeInit(USART_TypeDef* USARTx);

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

void USART_StructInit(USART_InitTypeDef* USART_InitStruct);

void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);
//配置同步时钟输出,包括时钟是不是要输出,时钟的极性相位等

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);
开启USART到DMA的触发通道

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
//发送数据(写DR寄存器)

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
//接收数据(读DR寄存器)DR寄存器内部有4个寄存器控制发送和接收

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
//标志位相关函数

3.串口初始化

void Serial_Init()
{
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//定义引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //TX用复用推挽输出,RX用输入模式 一般用
    //浮空或上拉。因为串口波形空闲状态是高电平,所以不使用下拉
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//初始化USART
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate  = 9600 ;//配置波特率
	USART_InitStructure.USART_HardwareFlowControl  = USART_HardwareFlowControl_None ;
    //硬件流控制 ,内容有不使用流控,只用CTS,只用RTS,或CTS,RTS都使用
	USART_InitStructure.USART_Mode  = USART_Mode_Tx ;
    //发送模式  ( USART_Mode_Tx|USART_Mode_Rx)发送和接收模式
	USART_InitStructure.USART_Parity  = USART_Parity_No ;// 校验位  无校验
	USART_InitStructure.USART_StopBits  = USART_StopBits_1 ;//停止位  选1位
	USART_InitStructure.USART_WordLength  = USART_WordLength_8b ;//字长  8位
	USART_Init(USART1, &USART_InitStructure);

    USART_Cmd(USART1, ENABLE);
}

4. USARTFA发送数据函数

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
//函数执行内容:Byte把数据传给Data,之后Data&01FF,即把无关的高位清零,然后赋值给DR寄存器
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) ;
//等待TXE置1 ,当数据从TDR寄存器转到发送位移寄存器时TXE才会置1
	//不需要手动清零

}
/**
  * @brief  Transmits single data through the USARTx peripheral.
  * @param  USARTx: Select the USART or the UART peripheral. 
  *   This parameter can be one of the following values:
  *   USART1, USART2, USART3, UART4 or UART5.
  * @param  Data: the data to transmit.
  * @retval None
  */
void USART_SendData(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);
}

5.主函数

int main(void)
{
	OLED_Init();
	Serial_Init();
	
	Serial_SendByte(0x41);
	//上电后,初始化串口,在调用串口发送0x41,TX引脚就会产生0X41的波形
	//这个波形可以发送给其他USB转串口的模块发送到电脑端

	
	while (1)
	{
		
	}
}

6.串口接收,可以使用中断和查询两种方法

如果使用查询,初始化就结束了,使用中断需要开启中断,配置NVIC

查询的流程:

1)在主函数里不断判断RXNE标志位,如果置1就说明接收数据了

2)调用ReceiveData,读取DR寄存器

中断的流程:

串口配置代码

#include "stm32f10x.h"                  // Device header
#include "stdio.h"
#include "stdarg.h"

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//定义引脚
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //TX用复用推挽输出,RX用输入模式 一般用浮空或上拉。因为串口波形空闲状态是高电平,所以不使用下拉
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;//接收复用再PA10
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //TX用复用推挽输出,RX用输入模式 一般用浮空或上拉。因为串口波形空闲状态是高电平,所以不使用下拉
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ;//接收复用再PA10
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//初始化USART
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate  = 9600 ;//配置波特率
	USART_InitStructure.USART_HardwareFlowControl  = USART_HardwareFlowControl_None ;//硬件流控制 ,内容有不使用流控,只用CTS,只用RTS,或CTS,RTS都使用
	USART_InitStructure.USART_Mode  = USART_Mode_Tx | USART_Mode_Rx;//发送模式  ( USART_Mode_Tx|USART_Mode_Rx)发送和接收模式
	USART_InitStructure.USART_Parity  = USART_Parity_No ;// 校验位  无校验
	USART_InitStructure.USART_StopBits  = USART_StopBits_1 ;//停止位  选1位
	USART_InitStructure.USART_WordLength  = USART_WordLength_8b ;//字长  8位
	USART_Init(USART1, &USART_InitStructure);

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,
//	USART的RXNE标志位一旦置1,就会向NVIC申请中断,之后就可以在中断函数接收数据

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断优先级分组为2
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel  = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd  = ENABLE ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 1 ;//优先级随便给
	NVIC_InitStructure.NVIC_IRQChannelSubPriority  =1 ;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}


//发送字节函数
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	//函数执行内容:Byte把数据传给Data,之后Data&01FF,即把无关的高位清零,然后赋值给DR寄存器
	
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) ;
	//等待TXE置1 ,当数据从TDR寄存器转到发送位移寄存器时TXE才会置1
	//不需要手动清零

}

void Serial_SendArray(uint8_t *Array, uint16_t Length)//发送一个数组  Length用于判断数组是否结束
{
	uint16_t i;
	for (i=0; i<Length; i++)
	{
		Serial_SendByte(Array[i]);
	}
}

//发送字符串,由于字符串自带结束位,所以不需要定义长度
void Serial_SendString(char*String)
{
	uint16_t i;
	
	//这里的0对应空字符,是字符串结束标志位
	for (i=0; String[i] != '\0'; i++)
	{
		Serial_SendByte(String[i]);
	}

}

//次方函数,函数的返回值=X^Y
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result*=X;
	}
	return Result;
}

//函数里需要把Number的,个位十位,百位等 以十进制拆分开,然后转换成字符,数字对应的数据,以此发送出去
//例如 12345 取万位就是12345/10000%10 = 1
//取千位就是12345/1000=12 再%10 =2 百位十位同理
void Serial_SendNumber(uint32_t Number, uint8_t Length) 
{
	uint8_t i;
	
	//假设Length为2,第一次循环2-0-1=1,10^1,就是发送10位,第二次循环2-1-1=0,10^0,就是发送个位
	for (i = 0; i < Length; i ++ )
	{
		Serial_SendByte(Number / Serial_Pow(10 ,Length - i -1) % 10 +0x30);  //加上0x30的原因是字符0对应的ASCLL码表是0X30,也可以加上  '0'
	}
	
}

//使用printf打印
//重定向fputc函数,这个函数是printf的底层 ,printf调用的函数
//这里把fputc重定向到了串口
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	
	return ch;
}

//*format 用来接收格式化字符串
//...用来接收可变参数列表
//可变参数用法
void Serial_Printf(char*format , ...)
{
	char String[100];
	va_list arg;//va_list是类型名,arg是变量名
	va_start(arg,format);//从format位置开始接收参数表,放在ARG里面
	vsprintf(String,format,arg);//打印位置是String,格式化字符串是format,参数表是arg   sprintf用于接收直接写的参数,封装要用vsprintf
	va_end(arg);//释放参数表
	Serial_SendString(String);//把String发送出去
	
}
	
//中断接收和变量的封装
uint8_t Serial_GetRxFlag(void)
{
	//读完数据后自动清除
	if (Serial_RxFlag == 1 )
	{
		Serial_RxFlag =0;
		return 1;//返回1
	}
	return 0;//否则返回0
}

//中断接收和变量的封装
uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;
}

//把数据进行了一次转存,最终还是要扫描查询RxFlag接受数据,对单字节意义不大
void USART1_IRQHandler(void)
{
	//如果RXNE确实置1了就进if,如果读取了DR,接可以自动清除标志位,不用手动清除
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		Serial_RxData = USART_ReceiveData(USART1);//接收数据
		Serial_RxFlag = 1; //读完数据后置1
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除中断标志位
	}
}

主函数代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t RxData;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1,1,"RxData:");
	Serial_Init();
	
	while (1)
	{
		if (Serial_GetRxFlag() == 1) //if成立说明收到数据了
		{
			RxData=Serial_GetRxData();//目前接收到的一个字节数据已经在RxData里了
			Serial_SendByte(RxData);//把接收到的数据回传到电脑
			OLED_ShowHexNum(1,8,RxData,2);
		
		}
	}
}

物联沃分享整理
物联沃-IOTWORD物联网 » 江科大32开发板USART串口发送教程

发表评论