2回答

0收藏

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

#竞赛 #竞赛 6976 人阅读 | 2 人回复 | 2013-08-26

本帖最后由 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));
}

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




分享到:
回复

使用道具 举报

回答|共 2 个

倒序浏览

沙发

sixyj

发表于 2013-8-26 13:32:34 | 只看该作者

楼主威武{:soso_e179:}
板凳

MMzhang-319191

发表于 2013-8-26 16:58:38 | 只看该作者

NB 啊啊                                            
心中有曲自然嗨!!!
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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