3.串口操作—基于CT117E开发板的STM32库函数编程
2017-01-23 10:03
615 查看
#工程中添加stm32f10x_uart.c #main函数中 #include "stm32f10x_usart.h"1. 串口时钟使能。串口是挂载在APB2下面的外设使能函数为
2. 串口复位。
当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是在函数 USART_DeInit()中完成:
比如我们要复位串口 1,方法为:
3. 串口参数初始化。
串口初始化是通过 USART_Init()函数实现的,
这个函数的的第一个入口参数是指定初始化的串口标号,这里选择 USART1。
第二个入口参数是一个 USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用来设置串口的一些参数。一般的实现格式为:
从上面的初始化格式可以看出初始化需要设置的参数为:波特率,字长,停止位,奇偶校验位,硬件数据流控制,模式(收,发)。我们可以根据需要设置这些参数。
4. 数据发送与接收。
STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到收据的时候,也是存在该寄存器内。STM32 库函数操作 USART_DR 寄存器发送数据的函数是:
通过该函数向串口寄存器 USART_DR 写入一个数据。
STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
通过该函数可以读取串口接受到的数据。
5. 串口状态。
串口的状态可以通过状态寄存器 USART_SR 读取。 USART_SR 的各位描述如下图所示
关注一下两个位,第 5、6 位 RXNE 和 TC
RXNE(读数据寄存器非空) ,当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。
这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。
TC(发送完成) ,当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。
如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:1)读 USART_SR,写USART_DR。2)直接向该位写 0。
固件库函数里面,读取串口状态的函数是:
这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,比如上面讲解的RXNE(读数据寄存器非空)以及 TC(发送完成)。
例如我们要判断读寄存器是否非空(RXNE),操作库函数的方法是:
要判断发送是否完成(TC),操作库函数的方法是:
这些标识号在 MDK里面是通过宏定义定义的:
6. 串口使能。串口使能是通过函数 USART_Cmd()来实现的,这个很容易理解,使用方法是:
7. 开启串口响应中断。有些时候当我们还需要开启串口中断,那么我们还需要使能串口中
断,使能串口中断的函数是:
这个函数的第二个入口参数是标示使能串口的类型,也就是使能哪种中断,因为串口的中断类型有很多种。比如在接收到数据的时候(RXNE 读数据寄存器非空) ,我们要产生中断,那么我们开启中断的方法是:USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断发送数据结束的时候(TC,发送完成)要产生中断,那么方法是:
8. 获取相应中断状态。当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄存器中的某个标志位。 经常我们在中断处理函数中, 要判断该中断是哪种中断, 使用的函数是:
比如我们使能了串口发送完成中断, 那么当中断发生了, 我们便可以在中断处理函数中调用这个函数来判断到底是否是串口发送完成中断,方法是:
返回值是 SET,说明是串口发送完成中断发生。
初始化串口的过程
① 串口时钟使能,GPIO 时钟使能
② 串口复位
③ GPIO 端口模式设置
④ 串口参数初始化
⑤ 初始化 NVIC 并且开启中断(否则只能发不能收)
⑥ 使能串口
下面是串口初始化函数USART_Config()
下面看怎么样用串口收发信息:
1.发信息
首先利用发信息的函数 USART_SendData(USART1,string[t]);//向串口1发送信息
接着要检测这个数据是否已经被发送完成了。USART_FLAG_TC 是宏定义的数据发送完成 标识符。
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
利用USART_SendString()发送字符串
如果发送字符则这样,区别在于参数是否是指针:
2.收信息
这里需要注意一点,因为我们使用到了串口的中断接收,必须在 usart.h 里面设置EN_USART1_RX 为 1(默认设置就是 1 的)。该函数才会配置中断使能,以及开启串口 1 的NVIC 中断。 还要编写中断服务函数。串口2 的中断服务数USART2_IRQHandler。在stm32f10x_it.c 中,编写中断函数,来处理串口接收的数据。
在主函数定义个数组
uint8_t USART_RXBUF[20];
这样在main函数判断到标志位为1,接收到数据时就可以使用这个数组
附:串口引脚定义
STM32F103xC、 STM32F103xD和STM32F103xE增强型系列产品中, 内置了3个通用同步/异步收发器(USART1、USART2和USART3),和2个通用异步收发器(UART4和UART5)。
具体引脚位置参考以下程序:
当然,以上的引脚并不唯一(存在ioremap=0,1的情况),如果要换引脚看手册。
APB2PeriphClockCmd(RCC_APB2Periph_USART1);
2. 串口复位。
当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是在函数 USART_DeInit()中完成:
void USART_DeInit(USART_TypeDef* USARTx);//串口复位
比如我们要复位串口 1,方法为:
USART_DeInit(USART1); //复位串口 1
3. 串口参数初始化。
串口初始化是通过 USART_Init()函数实现的,
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef*USART_InitStruct);
这个函数的的第一个入口参数是指定初始化的串口标号,这里选择 USART1。
第二个入口参数是一个 USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用来设置串口的一些参数。一般的实现格式为:
USART_InitStructure.USART_BaudRate = bound; //一般设置为 9600; 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); //初始化串口
从上面的初始化格式可以看出初始化需要设置的参数为:波特率,字长,停止位,奇偶校验位,硬件数据流控制,模式(收,发)。我们可以根据需要设置这些参数。
4. 数据发送与接收。
STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到收据的时候,也是存在该寄存器内。STM32 库函数操作 USART_DR 寄存器发送数据的函数是:
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
通过该函数向串口寄存器 USART_DR 写入一个数据。
STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
通过该函数可以读取串口接受到的数据。
5. 串口状态。
串口的状态可以通过状态寄存器 USART_SR 读取。 USART_SR 的各位描述如下图所示
关注一下两个位,第 5、6 位 RXNE 和 TC
RXNE(读数据寄存器非空) ,当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。
这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。
TC(发送完成) ,当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。
如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:1)读 USART_SR,写USART_DR。2)直接向该位写 0。
固件库函数里面,读取串口状态的函数是:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,比如上面讲解的RXNE(读数据寄存器非空)以及 TC(发送完成)。
例如我们要判断读寄存器是否非空(RXNE),操作库函数的方法是:
USART_GetFlagStatus(USART1, USART_FLAG_RXNE);
要判断发送是否完成(TC),操作库函数的方法是:
USART_GetFlagStatus(USART1, USART_FLAG_TC);
这些标识号在 MDK里面是通过宏定义定义的:
#define USART_IT_PE ((uint16_t)0x0028) #define USART_IT_TXE ((uint16_t)0x0727) #define USART_IT_TC ((uint16_t)0x0626) #define USART_IT_RXNE ((uint16_t)0x0525) #define USART_IT_IDLE ((uint16_t)0x0424) #define USART_IT_LBD ((uint16_t)0x0846) #define USART_IT_CTS ((uint16_t)0x096A) #define USART_IT_ERR ((uint16_t)0x0060) #define USART_IT_ORE ((uint16_t)0x0360) #define USART_IT_NE ((uint16_t)0x0260) #define USART_IT_FE ((uint16_t)0x0160)
6. 串口使能。串口使能是通过函数 USART_Cmd()来实现的,这个很容易理解,使用方法是:
USART_Cmd(USART1, ENABLE); //使能串口
7. 开启串口响应中断。有些时候当我们还需要开启串口中断,那么我们还需要使能串口中
断,使能串口中断的函数是:
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
这个函数的第二个入口参数是标示使能串口的类型,也就是使能哪种中断,因为串口的中断类型有很多种。比如在接收到数据的时候(RXNE 读数据寄存器非空) ,我们要产生中断,那么我们开启中断的方法是:USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断发送数据结束的时候(TC,发送完成)要产生中断,那么方法是:
USART_ITConfig(USART1,USART_IT_TC,ENABLE);
8. 获取相应中断状态。当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄存器中的某个标志位。 经常我们在中断处理函数中, 要判断该中断是哪种中断, 使用的函数是:
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
比如我们使能了串口发送完成中断, 那么当中断发生了, 我们便可以在中断处理函数中调用这个函数来判断到底是否是串口发送完成中断,方法是:
USART_GetITStatus(USART1, USART_IT_TC)
返回值是 SET,说明是串口发送完成中断发生。
初始化串口的过程
① 串口时钟使能,GPIO 时钟使能
② 串口复位
③ GPIO 端口模式设置
④ 串口参数初始化
⑤ 初始化 NVIC 并且开启中断(否则只能发不能收)
⑥ 使能串口
下面是串口初始化函数USART_Config()
void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //1.串口和GPIO口时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //2.GPIO端口初始化(TX输出) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //RX为输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); //3.串口参数初始化配置 USART_InitStructure.USART_BaudRate = 19200;//波特率 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(USART2, &USART_InitStructure); //初始化串口 //4.配置NVIC NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //打开串口2中断通道 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //抢占优先级1 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //子优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //IRQ 通道使能 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断优先级初始化 NVIC_Init(&NVIC_InitStructure); //5.打开串口中断 USART_ITConfig(USART2,USART_IT_RXNE,ENABLE); //6.使能串口 USART_Cmd(USART2, ENABLE); }
下面看怎么样用串口收发信息:
1.发信息
首先利用发信息的函数 USART_SendData(USART1,string[t]);//向串口1发送信息
接着要检测这个数据是否已经被发送完成了。USART_FLAG_TC 是宏定义的数据发送完成 标识符。
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
利用USART_SendString()发送字符串
void USART_SendString(int8_t *str) { uint8_t index = 0; do { USART_SendData(USART2,str[index]); while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET); index++; } while(str[index] != 0); //一直发到最后一个字 }
如果发送字符则这样,区别在于参数是否是指针:
uint8_t send_AHRSO[5]={0xFA,0X01,0x00,0x82,0X7B}; USART_PutHEX(USART1,send_AHRSO[0]); USART_PutHEX(USART1,send_AHRSO[1]); USART_PutHEX(USART1,send_AHRSO[2]); USART_PutHEX(USART1,send_AHRSO[3]); USART_PutHEX(USART1,send_AHRSO[4]); void USART_PutHEX(USART_TypeDef* USARTx,uint8_t Data) { USART_SendData(USARTx, Data); while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET); }
2.收信息
这里需要注意一点,因为我们使用到了串口的中断接收,必须在 usart.h 里面设置EN_USART1_RX 为 1(默认设置就是 1 的)。该函数才会配置中断使能,以及开启串口 1 的NVIC 中断。 还要编写中断服务函数。串口2 的中断服务数USART2_IRQHandler。在stm32f10x_it.c 中,编写中断函数,来处理串口接收的数据。
extern uint8_t USART_RXBUF[20];//使用外部变量 void USART2_IRQHandler(void) { uint8_t temp; if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET){ USART_ClearITPendingBit(USART2,USART_IT_RXNE);//清除标志位 temp = USART_ReceiveData(USART2); if((temp == 'x') || (RXCUNT == 20)){//如果有20字或结尾是X RXCUNT = 0; RXOVER = 1; //接收完成 USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);//关中断 } else{//否则,一直放到数组中 USART_RXBUF[RXCUNT] = temp; ++RXCUNT; } } }
在主函数定义个数组
uint8_t USART_RXBUF[20];
这样在main函数判断到标志位为1,接收到数据时就可以使用这个数组
if(RXOVER == 1){} 每次用完要清空它和标志位 for(i=0;i<20;i++){ USART_RXBUF[i] = 0; } RXOVER = 0;
附:串口引脚定义
STM32F103xC、 STM32F103xD和STM32F103xE增强型系列产品中, 内置了3个通用同步/异步收发器(USART1、USART2和USART3),和2个通用异步收发器(UART4和UART5)。
具体引脚位置参考以下程序:
//************************************************************* 管脚定义 //************************************************************* /*UART1 TXD*/ 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); /*UART1 RXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); //************************************************************* /*UART2 TXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); /*UART2 RXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); //************************************************************* /*UART3 TXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); /*UART3 RXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure); //************************************************************* /*UART4 TXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); /*UART4 RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOC, &GPIO_InitStructure); //************************************************************* /*UART5 TXD*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); /*UART5 RX */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPIO_InitStructure); //************************************************************* 添加中断 //************************************************************* /*串口1接收中断*/ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /*串口2接收中断*/ NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /*串口3接收中断*/ NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /*串口4接收中断*/ NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /*串口5接收中断*/ NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //*************************************************************
当然,以上的引脚并不唯一(存在ioremap=0,1的情况),如果要换引脚看手册。
相关文章推荐
- 5.LCD驱动调用方法以及按键函数编写—基于CT117E开发板的STM32库函数编程
- 6.外部中断—基于CT117E开发板的STM32库函数编程
- 8.内部温度传感器的使用—基于CT117E开发板的STM32库函数编程
- 1.点亮LED—基于CT117E开发板的STM32库函数编程
- 10.RTC内部时钟—基于CT117E开发板的STM32库函数编程
- 7.AD转换—基于CT117E开发板的STM32库函数编程
- 9.I2C读写数据—基于CT117E开发板的STM32库函数编程
- 14.知识点总结归纳—基于CT117E开发板的STM32库函数编程
- 2.系统延时函数—基于CT117E开发板的STM32库函数编程
- 11.通用定时器—基于CT117E开发板的STM32库函数编程
- 12.PWM—基于CT117E开发板的STM32库函数编程
- 基于STM32CT117E竞赛板(STM32f103RB) 使用USART串口发送数据
- Java中基于Rxtx的串口操作
- ARM的串口基本操作函数测试(基于LPC2134)
- 基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现(续)
- [S3C6410学习心得之一]ok6410开发板基于Ubuntu9.10开发环境搭建-串口
- 通过串口终端操作开发板
- Java中基于Rxtx的串口操作
- 在基于OMAP3530的DevKit8000开发板上实现Linux操作系统下的GPIO读写操作
- 【S3C6410学习心得之一】ok6410开发板基于Ubuntu9.10开发环境搭建-串口