打印
[STM32F4]

【STM32F4探索套件】序列之6:串口通信

[复制链接]
6082|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 outstanding 于 2014-3-16 22:34 编辑

本节我们将串口简介、串口原理、硬件设计、软件设计和下载验证5部分来分析,主要是从下面5个方面进行讲解:
1.STM32F4串口部分介绍
2.STM32F429简单串口原理介绍
3.硬件设计
4.软件设计
5.下载验证
一、串口的简介【通用同步异步收发器 USART
实现功能:上电一直打印一串字符串。下面简单介绍一下USART的特性:
二、简单介绍原理
通信使用 3 根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
STM32fF429引脚:
RXD -- PA10 接收数据线
TXD -- PA9  发送数据线
串口软件编写的一般步骤:
(a) 串口时钟使能,GPIO时钟使能
(b) 串口复位
(c) GPIO端口模式设置
(d) 串口参数初始化
(e) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
(f) 使能串口
(g) 编写串口中断处理函数
为了更好了解固件库在串口配置中的使用,下面简单介绍几个与串口有关的固件库函数。这些函数和定义主要在stm32f4xx_usart.c stm32f4xx_usart.h 中。
(a) 串口时钟使能函数。USART挂载在APB2总线上,所以使能函数为:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE );
(b) 串口复位函数。当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设才做。复位是在函数USART_DeInit()完成。
USART_DeInit(USART_TypeDef* USARTx)
(c) 串口参数初始化。串口初始化是通过USART_Init()函数来实现的。
USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)
(d) 数据发送与接收。STM32 的发送与接收是通过数据寄存器 USART_RDRUSART_TDR来实现的,当向USART_TDR寄存器写数据的时候,串口就会自动发送数据,当收到数据的时候,就存储在USART_RDR寄存器中。
STM32 库函数操作 USART_TDR 寄存器发送数据的函数是:
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
通过该函数可以向串口寄存器写一个数据。
STM32 库函数操作 USART_RDR 寄存器读取串口接收到的数据的函数是:
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
通过该函数可以读取串口接受到的数据。
(e) 串口状态。
读取串口状态的函数是:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
第二个入口参数非常关键,它是我们要查看串口的哪种状态。
(f) 串口使能。串口使能是通过函数USART_Cmd()来实现的。
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
(g) 开启串口响应中断。有时候当我们还需要开启串口中断,那么我们还需要使能串口中断,使能串口中断的函数是:
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
(h) 获取相应的中断状态。当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄存器中的某个标志位。 经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
具体可以参考《STM32F030参考手册》。
三、硬件设计
硬件比较简单就是两个引脚!!
四、软件设计
软件是参考网上的一个程序,等下传上附件!!!
void uart_init(u32 bound){
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
         
          /* Enable GPIOC and GPIOE clock */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
        
          /* Enable USART1 APB clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
          /* USART1 Pins configuration ************************************************/
  /* Connect pin to Periph */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);   
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
        
  /* Configure pins as AF pushpull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);             //TX
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);             //RX
   //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;//一般设置为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); //初始化串口
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART1, ENABLE);                    //使能串口
}
void USART1_IRQHandler(void)                        //串口1中断服务程序
        {
        u8 Res;
#ifdef OS_TICKS_PER_SEC                 //如果时钟节拍数定义了,说明要使用ucosII.
        OSIntEnter();   
#endif
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
                {
                Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据
               
                if((USART_RX_STA&0x8000)==0)//接收未完成
                        {
                        if(USART_RX_STA&0x4000)//接收到了0x0d
                                {
                                if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
                                else USART_RX_STA|=0x8000;        //接收完成了
                                }
                        else //还没收到0X0D
                                {        
                                if(Res==0x0d)USART_RX_STA|=0x4000;
                                else
                                        {
                                        USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                                        USART_RX_STA++;
                                        if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收         
                                        }                 
                                }
                        }                    
     }
#ifdef OS_TICKS_PER_SEC                 //如果时钟节拍数定义了,说明要使用ucosII.
        OSIntExit();                                                                                          
#endif
}
五、下载验证
整个程序在附件里面,希望大家验证!!!


stm32f429 USART.zip (564.26 KB)



沙发
coolfei| | 2014-3-20 11:25 | 只看该作者
好东西,支持一下

使用特权

评论回复
板凳
outstanding|  楼主 | 2014-3-20 11:47 | 只看该作者
coolfei 发表于 2014-3-20 11:25
好东西,支持一下

:handshake

使用特权

评论回复
地板
电子write_cai| | 2014-4-8 16:30 | 只看该作者
outstanding 发表于 2014-3-20 11:47

我怎么试了你的代码没有反应~

使用特权

评论回复
5
电子write_cai| | 2014-4-11 13:26 | 只看该作者
outstanding 发表于 2014-3-20 11:47

你QQ 多少啊。问你点问题

使用特权

评论回复
6
outstanding|  楼主 | 2014-4-11 14:21 | 只看该作者
电子write_cai 发表于 2014-4-11 13:26
你QQ 多少啊。问你点问题

你是什么问题?你最好外接一个带串口的芯片如MAX232 在试试看

使用特权

评论回复
7
拿起书本| | 2014-4-14 15:15 | 只看该作者
值的学习,下载看年,貌似我的也没有反应啊,继续研究中……

使用特权

评论回复
8
电子write_cai| | 2014-4-18 13:02 | 只看该作者
outstanding 发表于 2014-4-11 14:21
你是什么问题?你最好外接一个带串口的芯片如MAX232 在试试看

我就是接max232的。现在我能用PB6,7 做uasrt。唯独PA9,10不行。

使用特权

评论回复
9
outstanding|  楼主 | 2014-4-18 13:12 | 只看该作者
电子write_cai 发表于 2014-4-18 13:02
我就是接max232的。现在我能用PB6,7 做uasrt。唯独PA9,10不行。

还有这种事情  你现在可以么?

使用特权

评论回复
10
电子write_cai| | 2014-4-18 13:19 | 只看该作者
outstanding 发表于 2014-4-18 13:12
还有这种事情  你现在可以么?

我先在不用PA9,10、 就用PB6,7 但PB6已经被LCD 数据线使用了。

使用特权

评论回复
11
叮叮当| | 2014-4-21 12:47 | 只看该作者
pa9 ,pa10 和 tx,rx 之间有个电阻要自己链接的。

使用特权

评论回复
12
keniking| | 2014-10-5 17:03 | 只看该作者
叮叮当 发表于 2014-4-21 12:47
pa9 ,pa10 和 tx,rx 之间有个电阻要自己链接的。

  请问加电阻怎么弄??是不是不加就会出现接收与发送数值都会改变?我现在发送、接收的数据都不一样,搞得收到的数据跟随机数一样

使用特权

评论回复
13
周董| | 2014-10-5 23:36 | 只看该作者
学习了,楼主很厉害!!

使用特权

评论回复
14
outstanding|  楼主 | 2014-10-6 08:17 | 只看该作者
周董 发表于 2014-10-5 23:36
学习了,楼主很厉害!!

过奖了 菜鸟一个

使用特权

评论回复
15
十日西豪| | 2014-10-17 17:32 | 只看该作者
请问一下,我的代码和版主的差不都,为什么发送没有问题,接收有问题!!我的代码如下
void USER_USARTx_Init(void)
{
                GPIO_InitTypeDef                                                         GPIO_InitStruct;
                USART_InitTypeDef                                                 USART_InitStruct;
                USART_ClockInitTypeDef                                USART_ClockInitStruct;
                NVIC_InitTypeDef                                                        NVIC_InitStruct;
                uint16_t        i,j;
               
/* Enable USART1 clocks */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);                                       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
       
/**IO SET INIT        **/       
  GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_9|GPIO_Pin_10;
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;
        GPIO_Init(GPIOA, &GPIO_InitStruct);
       
       
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
/** RESET USART**/
                USART_DeInit(USART1);
               
/** USART1 DATA INIT**/
                USART_InitStruct.USART_BaudRate = 9600;
                USART_InitStruct.USART_WordLength = USART_WordLength_8b;
                USART_InitStruct.USART_StopBits = USART_StopBits_1;
                USART_InitStruct.USART_Parity = USART_Parity_No ;
                USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
                USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
                USART_Init(USART1, &USART_InitStruct);
       
/** USART1 CLOCK INIT**/
                USART_ClockInitStruct.USART_Clock=USART_Clock_Disable;//USART_Clock_Enable;
                USART_ClockInitStruct.USART_CPOL = USART_CPOL_Low;
                USART_ClockInitStruct.USART_CPHA = USART_CPHA_1Edge;
                USART_ClockInitStruct.USART_LastBit = USART_LastBit_Disable;//USART_LastBit_Enable;
                USART_ClockInit(USART1, &USART_ClockInitStruct);
               
/** USART1 INTERRUPT INIT **/       
                NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
                NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=3;
                NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
                NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;       
                NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);               
                NVIC_Init(&NVIC_InitStruct);               

                USART_ITConfig(USART1, USART_IT_TC,DISABLE);       
                USART_ITConfig(USART1, USART_IT_RXNE,DISABLE);
               
       
/** USART1 ENABLE**/       
                USART_HalfDuplexCmd(USART1, ENABLE);       
                USART_ITConfig(USART1,USART_IT_RXNE, ENABLE);       
                USART_Cmd(USART1,ENABLE);       

/** USART1  SENT**/
        for(j=0x1f;j<0x7f;j++)
                {
                        USART_SendData(USART1,j);
                        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET)                       
                        for(i=0;i<60000;i++);
                        for(i=0;i<60000;i++);
                        for(i=0;i<60000;i++);
                }
        while(1)
        {
                aUSATRxBUF = USART_ReceiveData(USART1) ;
                __nop();
        }       
}
void USART1_IRQHandler(void)
{
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
  {
    /* Read one byte from the receive data register */
                        aUSATRxBUF = (USART_ReceiveData(USART1) & 0x7F);
                        USART_ClearFlag(USART1,USART_FLAG_RXNE);
                        USART_ClearITPendingBit(USART1, USART_IT_RXNE);               
                        __nop();
  }
}
串口中断就是进不去啊!望各路高手指点一下!!!            

使用特权

评论回复
16
十日西豪| | 2014-10-17 17:50 | 只看该作者
哦!sorry!多加了一个这个!USART_HalfDuplexCmd(USART1, ENABLE);

使用特权

评论回复
17
outstanding|  楼主 | 2014-10-17 21:16 | 只看该作者
十日西豪 发表于 2014-10-17 17:50
哦!sorry!多加了一个这个!USART_HalfDuplexCmd(USART1, ENABLE);

:lol   找到问题就好

使用特权

评论回复
18
Jack67| | 2017-8-16 20:12 | 只看该作者
请问,有奇偶校验位的范例吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:QQ:2550634286   可接项目和毕设等                   可以出售各种LED灯,控制类产品和                   控制类方案。

378

主题

4015

帖子

11

粉丝