前面《ZigBee 3.0实战教程-Silicon Labs EFR32+EmberZnet-5-01:片上资源详解》一文中提到了,EFR32MG21总共有3个串口,分别为USART0、USART1和USART2,具体GPIO的映射情况如下图所示:
(注:如上内容部分截取自EFR32MG21的Datasheet中的“Table 6.4. DBUS Routing Table”。)
由上图可见:
- USART0:相关引脚可以映射到PA、PB、PC和PD总共4组GPIO的任意一个GPIO上;
- USART1:相关引脚可以映射到PA和PB总共2组GPIO的任意一个GPIO上;
- USART2:相关引脚可以映射到PC和PD总共2组GPIO的任意一个GPIO上。
一、初始化
首先需要在双击pintool文件之后弹出的界面中设置好所需使用的串口引脚,如下图所示:
上图中框出的部分就是为启用串口所新增的改动。然后在工程中的任意位置增加下面这段初始化代码即可:
void my_usart0_init(uint32_t baudrate)
{
// Enable clock to GPIO
CMU_ClockEnable(cmuClock_GPIO, true);
// Configure the USART TX/RX pin
GPIO_PinModeSet(MY_USART0_TX_PORT, MY_USART0_TX_PIN, gpioModePushPull, 0);
GPIO_PinModeSet(MY_USART0_RX_PORT, MY_USART0_RX_PIN, gpioModeInput, 0);
// Route MY_USART0 TX and RX to the board controller TX and RX pins
GPIO->USARTROUTE[MY_USART0_NUM].TXROUTE = (MY_USART0_TX_PORT << _GPIO_USART_TXROUTE_PORT_SHIFT) | (MY_USART0_TX_PIN << _GPIO_USART_TXROUTE_PIN_SHIFT);
GPIO->USARTROUTE[MY_USART0_NUM].RXROUTE = (MY_USART0_RX_PORT << _GPIO_USART_RXROUTE_PORT_SHIFT) | (MY_USART0_RX_PIN << _GPIO_USART_RXROUTE_PIN_SHIFT);
GPIO->USARTROUTE[MY_USART0_NUM].ROUTEEN = GPIO_USART_ROUTEEN_RXPEN | GPIO_USART_ROUTEEN_TXPEN;
// Configure and enable MY_USART0
USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
init.baudrate = baudrate;
init.databits = MY_USART0_DATA_BITS;
init.parity = MY_USART0_PARITY;
init.stopbits = MY_USART0_STOP_BITS;
init.oversampling = MY_USART0_OVER_SAMPLING;
init.hwFlowControl = MY_USART0_HW_FLOW_CONTROL;
USART_InitAsync(MY_USART0, &init);
// Enable NVIC USART sources
NVIC_ClearPendingIRQ(MY_USART0_RX_IRQ_N);
NVIC_EnableIRQ(MY_USART0_RX_IRQ_N);
// Enable receive data valid interrupt
USART_IntEnable(MY_USART0, USART_IEN_RXDATAV);
}
二、发送
本专题系列博客推荐使用EmberZnet自带的发送函数USART_Tx()
进行串口数据发送,该函数的定义在文件em_usart.c内,具体如下图所示:
/***************************************************************************//**
* @brief
* Transmit one 4-9 bit frame.
*
* @details
* Depending on the frame length configuration, 4-8 (least significant) bits from
* @p data are transmitted. If the frame length is 9, 8 bits are transmitted from
* @p data and one bit as specified by CTRL register, BIT8DV field.
* See USART_TxExt() for transmitting 9 bit frame with full control of
* all 9 bits.
*
* Notice that possible parity/stop bits in asynchronous mode are not
* considered part of a specified frame bit length.
*
* @note
* This function will stall if the buffer is full until the buffer becomes available.
*
* @param[in] usart
* A pointer to the USART/UART peripheral register block.
*
* @param[in] data
* Data to transmit. See details above for more information.
******************************************************************************/
void USART_Tx(USART_TypeDef *usart, uint8_t data)
{
/* Check that transmit buffer is empty */
while (!(usart->STATUS & USART_STATUS_TXBL)) {
}
usart->TXDATA = (uint32_t)data;
}
需要发送一个字节的数据时,直接调用上述函数即可,当需要发送多字节数据时,循环、连续调用该函数即可,如下:
void my_usart0_send_buf(uint8_t *buf, uint16_t len)
{
uint16_t i;
for(i=0; i<len; i++)
{
USART_Tx(MY_USART0, buf[i]);
}
}
printf格式化输出:
int my_usart0_printf(const char* format, ...)
{
char buf[MY_USART0_PRINT_MAX] = {0x00};
va_list va;
int ret;
va_start(va, format);
ret = vsprintf(buf, format, va);
va_end(va);
my_usart0_send_buf((uint8_t *)buf, strlen((const char *)buf));
return ret;
}
三、实验
在工程中的任意位置增加如下代码:
void emberAfMainInitCallback(void)
{
my_usart0_printf(hello world!\r\n);
}
即为在回调函数emberAfMainInitCallback()
中调用串口打印函数输出 hello world! 字符串并换行。编译烧录后,按一下开发板上的复位按键,即可看到电脑上的串口调试助手可以收到如下图所示的数据:
上图中框出的部分,就是我们增加的代码产生的效果,感兴趣的朋友可以自行修改相应代码,再编译,再烧录,观察实验现象的变化。
(注:任何相关问题,欢迎在文末技术交流QQ群中交流讨论。)