TA的每日心情 | 开心 2013-7-2 13:29 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到
|
本帖最后由 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));
}
对于接收函数,我觉得还是使用中断比较好,如果在那一直等待数据到达,其他什么也干不了。那么结束数据串就下次再说了。
|
|