查看: 5909|回复: 2

徐州工程学院(HOT详细讲解)STM32和zigbee之串口库函数使用1

[复制链接]
  • TA的每日心情
    开心
    2013-7-2 13:29
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-8-26 13:22:38 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 shen2008jie 于 2013-8-26 13:23 编辑

    好了。前些天具体从某一模块的c51程序,移植到STM32F4上,那么可以知道GPIO的使用,和系统定时器的使用。那么今天由于项目需要使用到串口和zigbee进行通讯,所以下面就是怎么使用串口。


    分割线---------------------------------------------------------------------------------
    使用过stm芯片的大都会知道怎么使用。这里就当作是初学者的文章,来叙述。
    首先去下一个STM32F4-Discovery_FW_V1.1.0
    STM32F4-Discovery_FW_V1.1.0\Project\Peripheral_Examples
    在里面可以找到官方的例程。虽然没有Usart但是STM32F1的应该是个它通用的。
    我们先看例程的代码:
    /* USARTx configured as follow:
            - BaudRate = 9600 baud  
            - Word Length = 8 Bits
            - One Stop Bit
            - No parity
            - Hardware flow control disabled (RTS and CTS signals)
            - Receive and transmit enabled
      */
      USART_InitTypeDef USART_InitStructure;


      USART_InitStructure.USART_BaudRate = 9600;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      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;


      STM_EVAL_COMInit(COM1, &USART_InitStructure);

    第一句是我从历程上面弄下来的。  USART_InitTypeDef USART_InitStructure;及是建立一个结构体。
    第二步,就是更改结构体里面的成员。我们来看看这个结构体里面是什么。 在编译器里鼠标对着USART_InitTypeDef这个右击进入看成员。如下:
    typedef struct
    {
      uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.
                                               The baud rate is computed using the following formula:
                                                - IntegerDivider = ((PCLKx) / (8 * (OVR8+1) * (USART_InitStruct->USART_BaudRate)))
                                                - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 8 * (OVR8+1)) + 0.5
                                               Where OVR8 is the "oversampling by 8 mode" configuration bit in the CR1 register. */


      uint16_t USART_WordLength;          /*!< Specifies the number of data bits transmitted or received in a frame.
                                               This parameter can be a value of @ref USART_Word_Length */


    uint16_t USART_StopBits;            /*!< Specifies the number of stop bits transmitted.
                                               This parameter can be a value of @ref USART_Stop_Bits */


    uint16_t USART_Parity;              /*!< Specifies the parity mode.
                                               This parameter can be a value of @ref USART_Parity
                                               @note When parity is enabled, the computed parity is inserted
                                                     at the MSB position of the transmitted data (9th bit when
                                                     the word length is set to 9 data bits; 8th bit when the
                                                     word length is set to 8 data bits). */

      uint16_t USART_Mode;                /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
                                               This parameter can be a value of @ref USART_Mode */


      uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
                                               or disabled.
                                               This parameter can be a value of @ref USART_Hardware_Flow_Control */
    } USART_InitTypeDef;

    可以看出来这些代码:
    USART_InitStructure.USART_BaudRate = 9600;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      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;

    就是对结构体里面的内容进行更改。那么更改,只是对存储的结构体改变内存,正真的设置还没有进行,那么下一句:
    STM_EVAL_COMInit(COM1, &USART_InitStructure);
    就是将你准备怎么设置的值装入到STM32的设置寄存器中。好的那么我们看看  
    STM_EVAL_COMInit(COM1, &USART_InitStructure);
    这个函数里面到底是什么。
    代码查看:
    /**
      * @brief  Configures COM port.
      * @param  COM: Specifies the COM port to be configured.
      *   This parameter can be one of following parameters:   
      *     @arg COM1
      *     @arg COM2  
      * @param  USART_InitStruct: pointer to a USART_InitTypeDef structure that
      *   contains the configuration information for the specified USART peripheral.
      * @retval None
      */
    蓝色代表的是源代码。红色的是我加的解释

    void STM_EVAL_COMInit(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct)

    STM_EVAL_COMInit(COM1, &USART_InitStructure);  输入了COM1,和刚才配置的USART_InitStructure 结构体
    这里看一下COM1是怎么来的,是联合体。COM1 代表0。
    typedef enum
    {
      COM1 = 0,
      COM2 = 1,
      COM3 = 2,
      COM4 = 3,
      COM5 = 4,
      COM6 = 5,
    } COM_TypeDef;
    {
      GPIO_InitTypeDef GPIO_InitStructure;
      新建管脚设置结构体,准备设置管脚。
      /* Enable GPIO clock */
      RCC_AHB1PeriphClockCmd(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM], ENABLE);
      开管脚的时钟,这对于STM32是很正常了(开时钟,设置,使能)
       /* Enable UART clock */
      RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
      因为要用到USART,所以还要开USART时钟。
      /* Connect PXx to USARTx_Tx*/
      GPIO_PinAFConfig(COM_TX_PORT[COM], COM_TX_PIN_SOURCE[COM] , COM_TX_AF[COM]);
    这个函数在下方的棕色字体给出代码,其实主要意思就是管脚的复用功能设置。设置TX管脚。这里根据不同的COMx可以不同设置,主要是由于COM_TX_PORT[COM]COM_TX_PIN_SOURCE[COM]COM_TX_AF[COM]这三个参数来的。
    ——————————————详细——————————————
    为了帮助理解我还是仔细讲解一下。这里就举个例子。COM_TX_PORT[COM] 查看其定义。
    看这个GPIO_TypeDef*             COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT, EVAL_COM2_TX_GPIO_PORT};
    是个结构体数组COM_TX_PORT[COMn]
    其中#define COMn                             2
    也就是数组有两个内容,COM_TX_PORT[COM] {0 EVAL_COM1_TX_GPIO_PORT,  1 EVAL_COM2_TX_GPIO_PORT}
    根据函数的STM_EVAL_COMInit(COM1, &USART_InitStructure);
    这个调用,那么COM_TX_PORT[COM]  其实就是COM_TX_PORT[0
    也就是GPIO_TypeDef* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT, EVAL_COM2_TX_GPIO_PORT}; 中的 EVAL_COM1_TX_GPIO_PORT
    好的这里再看看EVAL_COM1_TX_GPIO_PORT 是什么:#define EVAL_COM1_TX_GPIO_PORT           GPIOC
    那么就知道这里设置的是GPIOC
    那对于COM1其实就是GPIOC端口的,至于那个管脚就是 COM_TX_PIN_SOURCE[COM] 这个了,自己可以看代码。知道是哪个管脚。#define EVAL_COM1_TX_SOURCE              GPIO_PinSource6
    下面的就是省略了。
    ————————————————————————————————


      /* Connect PXx to USARTx_Rx*/
      GPIO_PinAFConfig(COM_RX_PORT[COM], COM_RX_PIN_SOURCE[COM], COM_RX_AF[COM]);
    这个函数在下方的棕色字体给出代码,其实主要意思就是管脚的复用功能设置。设置RX管脚。(同上)
      /* Configure USART Tx as alternate function  */
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
      GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COM];
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(COM_TX_PORT[COM], &GPIO_InitStructure);
    这个是设置TX管脚的具体的设置功能形式。

      /* Configure USART Rx as alternate function  */
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
      GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COM];
      GPIO_Init(COM_RX_PORT[COM], &GPIO_InitStructure);
    这个是设置RX管脚的具体的设置功能形式。

      /* USART configuration */
      USART_Init(COM_USART[COM], USART_InitStruct);
        这个是把设置的所有USART信息的结构体,全部设置到设计寄存器中。完成初始化。
      /* Enable USART */
      USART_Cmd(COM_USART[COM], ENABLE);
    这个就是俗话说的出试卷完了,就开始工作的开关使能了。
    }


    void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF) 源代码:
    /**
      * @brief  Changes the mapping of the specified pin.
      * @param  GPIOx: where x can be (A..I) to select the GPIO peripheral.
      * @param  GPIO_PinSource: specifies the pin for the Alternate function.
      *         This parameter can be GPIO_PinSourcex where x can be (0..15).
      * @param  GPIO_AFSelection: selects the pin to used as Alternate function.
      *          This parameter can be one of the following values:
      *            @arg GPIO_AF_RTC_50Hz: Connect RTC_50Hz pin to AF0 (default after reset)
      *            @arg GPIO_AF_MCO: Connect MCO pin (MCO1 and MCO2) to AF0 (default after reset)
      *            @arg GPIO_AF_TAMPER: Connect TAMPER pins (TAMPER_1 and TAMPER_2) to AF0 (default after reset)
      *            @arg GPIO_AF_SWJ: Connect SWJ pins (SWD and JTAG)to AF0 (default after reset)
      *            @arg GPIO_AF_TRACE: Connect TRACE pins to AF0 (default after reset)
      *            @arg GPIO_AF_TIM1: Connect TIM1 pins to AF1
      *            @arg GPIO_AF_TIM2: Connect TIM2 pins to AF1
      *            @arg GPIO_AF_TIM3: Connect TIM3 pins to AF2
      *            @arg GPIO_AF_TIM4: Connect TIM4 pins to AF2
      *            @arg GPIO_AF_TIM5: Connect TIM5 pins to AF2
      *            @arg GPIO_AF_TIM8: Connect TIM8 pins to AF3
      *            @arg GPIO_AF_TIM9: Connect TIM9 pins to AF3
      *            @arg GPIO_AF_TIM10: Connect TIM10 pins to AF3
      *            @arg GPIO_AF_TIM11: Connect TIM11 pins to AF3
      *            @arg GPIO_AF_I2C1: Connect I2C1 pins to AF4
      *            @arg GPIO_AF_I2C2: Connect I2C2 pins to AF4
      *            @arg GPIO_AF_I2C3: Connect I2C3 pins to AF4
      *            @arg GPIO_AF_SPI1: Connect SPI1 pins to AF5
      *            @arg GPIO_AF_SPI2: Connect SPI2/I2S2 pins to AF5
      *            @arg GPIO_AF_SPI3: Connect SPI3/I2S3 pins to AF6
      *            @arg GPIO_AF_I2S3ext: Connect I2S3ext pins to AF7
      *            @arg GPIO_AF_USART1: Connect USART1 pins to AF7
      *            @arg GPIO_AF_USART2: Connect USART2 pins to AF7
      *            @arg GPIO_AF_USART3: Connect USART3 pins to AF7
      *            @arg GPIO_AF_UART4: Connect UART4 pins to AF8
      *            @arg GPIO_AF_UART5: Connect UART5 pins to AF8
      *            @arg GPIO_AF_USART6: Connect USART6 pins to AF8
      *            @arg GPIO_AF_CAN1: Connect CAN1 pins to AF9
      *            @arg GPIO_AF_CAN2: Connect CAN2 pins to AF9
      *            @arg GPIO_AF_TIM12: Connect TIM12 pins to AF9
      *            @arg GPIO_AF_TIM13: Connect TIM13 pins to AF9
      *            @arg GPIO_AF_TIM14: Connect TIM14 pins to AF9
      *            @arg GPIO_AF_OTG_FS: Connect OTG_FS pins to AF10
      *            @arg GPIO_AF_OTG_HS: Connect OTG_HS pins to AF10
      *            @arg GPIO_AF_ETH: Connect ETHERNET pins to AF11
      *            @arg GPIO_AF_FSMC: Connect FSMC pins to AF12
      *            @arg GPIO_AF_OTG_HS_FS: Connect OTG HS (configured in FS) pins to AF12
      *            @arg GPIO_AF_SDIO: Connect SDIO pins to AF12
      *            @arg GPIO_AF_DCMI: Connect DCMI pins to AF13
      *            @arg GPIO_AF_EVENTOUT: Connect EVENTOUT pins to AF15
      * @retval None
      */
    void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
    {
      uint32_t temp = 0x00;
      uint32_t temp_2 = 0x00;
      
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
      assert_param(IS_GPIO_AF(GPIO_AF));
      
      temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;
      GPIOx->AFR[GPIO_PinSource >> 0x03] &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;
      temp_2 = GPIOx->AFR[GPIO_PinSource >> 0x03] | temp;
      GPIOx->AFR[GPIO_PinSource >> 0x03] = temp_2;
    }


    那么整个USART的初始化就ok了。
    总结一下怎么设置。

      USART_InitTypeDef USART_InitStructure;
      USART_InitStructure.USART_BaudRate = 9600;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      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;
      STM_EVAL_COMInit(COM1, &USART_InitStructure);
    (其中所用的函数官方是由相应程序的。这里初始化参数的选择就是这里改动,比如波特率在  USART_InitStructure.USART_BaudRate = 9600; 这里改)



    好的既然已经知道怎么初始化,但是怎么使用串口呢。
    我们先看则呢么发送一个字节数据的代码怎么写。TX
    还是看库代码:
    /**
      * @brief  Transmits single data through the USARTx peripheral.
      * @param  USARTx: where x can be 1, 2, 3, 4, 5 or 6 to select the USART or
      *         UART peripheral.
      * @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);
    }
    也就是说调用 USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
    就可以发送一个数据。
    例子:
      USART_SendData(EVAL_COM1, (uint8_t) ch);
      这个ch就是要发的数据,8位的。
      while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET);
      这个很关键,这个事查询发送完毕的,也就是说,如果没法送完毕,他就在这里做空循环,直到发送完毕。

    下面看看怎么接收一个字节。
    先贴代码:
    /**
      * @brief  Returns the most recent received data by the USARTx peripheral.
      * @param  USARTx: where x can be 1, 2, 3, 4, 5 or 6 to select the USART or
      *         UART peripheral.
      * @retval The received data.
      */
    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);
    }
    也就是说调用 uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
    就可以发送一个数据。
    例子:
            while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_RXNE) == RESET);
    查询式的等待接收完毕一个数据。只有接受完,才跳出来。
            ch = USART_ReceiveData(EVAL_COM1);
    跳出来后,就把得到的值付给数组ch中。
    或者这样写:
    if(USART_GetFlagStatus(EVAL_COM1, USART_FLAG_RXNE) != RESET)   //接收中断
                    {
                    ch = USART_ReceiveData(EVAL_COM1);         //读取接收到的数据
                    }

    上面所说的TX和RX都是查询式的,下一步则会说中断式的串口使用。


    通过学会使用法一个数据,和售一个数据这里还可以发一串数据和接收一串数据。
    这里就只贴一些代码,我想应该会看得懂。
    void UsartSend(uint8_t ch)
    {
      USART_SendData(EVAL_COM1,  ch);
      这个ch就是要发的数据,8位的。
      while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET);
      这个很关键,这个事查询发送完毕的,也就是说,如果没法送完毕,他就在这里做空循环,直到发送完毕。 }
    //输出字符串
    void PrintChar(const char *s)
    {
            const char *p;
            p=s;
            while(*p != '\0')
            {
                    UsartSend(*p);
                    p++;
            }
    }
    void PrintHexInt16(int16_t num)
    {
            UsartSend((num & 0xff00) >> 8);//先发送高8位,再发送低8位
            UsartSend((uint8_t)(num & 0x00ff));
    }

    对于接收函数,我觉得还是使用中断比较好,如果在那一直等待数据到达,其他什么也干不了。那么结束数据串就下次再说了。




    回复

    使用道具 举报

  • TA的每日心情
    难过
    2013-9-5 10:34
  • 签到天数: 7 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2013-8-26 13:32:34 | 显示全部楼层
    楼主威武{:soso_e179:}
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2014-6-4 13:58
  • 签到天数: 188 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2013-8-26 16:58:38 | 显示全部楼层
    NB 啊啊                                            
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-5-21 10:22 , Processed in 0.126317 second(s), 19 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.