本篇主要实现的是掌握USART通讯,能够实现数据的收发操作,串口的接收使用中断机制;基于USART功能添加SHELL程序,通过操作LED灯来实现一个简单的SHELL控制调用。
1.USART通讯
开发板上提供了USB转UART部分的硬件电路,我们只需要一根Micro USB线将开发板与电脑进行连接,WIN10系统电脑会自动识别并安装USB转串口有驱动程序,再结合MCU的USART3接口,可以实现MCU与电脑端的串口数据通讯;
USART初始化配置程序:将USART配置成115200(波特率),N(校验位),8(数据位),1(停止位),使能串口的接收和发送功能,使能接收中断功能并配置接收中断;配置GPIO引脚复用成USART功能引脚,如下程序所示:
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void UsartRxIrqCallback(void)
{
printf("%c", USART_RecData(M4_USART3));
USART_FuncCmd(M4_USART3, UsartTxAndTxEmptyInt, Enable);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void UsartErrIrqCallback(void)
{
if(USART_GetStatus(M4_USART3, UsartFrameErr) != Reset)
{
USART_ClearStatus(M4_USART3, UsartFrameErr);
}
if(USART_GetStatus(M4_USART3, UsartParityErr) != Reset)
{
USART_ClearStatus(M4_USART3, UsartParityErr);
}
if(USART_GetStatus(M4_USART3, UsartOverrunErr) != Reset)
{
USART_ClearStatus(M4_USART3, UsartOverrunErr);
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void USART3_Configure(void)
{
stc_irq_regi_conf_t stcIrqRegiCfg;
const stc_usart_uart_init_t stcInitCfg =
{
UsartIntClkCkNoOutput,
UsartClkDiv_1,
UsartDataBits8,
UsartDataLsbFirst,
UsartOneStopBit,
UsartParityNone,
UsartSamleBit8,
UsartStartBitFallEdge,
UsartRtsEnable,
};
/* Enable peripheral clock */
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USART3, Enable);
/* Initialize USART IO */
PORT_SetFunc(PortE, Pin04, Func_Usart3_Rx, Disable);
PORT_SetFunc(PortE, Pin05, Func_Usart3_Tx, Disable);
/* Initialize UART */
if(USART_UART_Init(M4_USART3, &stcInitCfg) != Ok)
{
while(1);
}
/* Set baudrate */
if(USART_SetBaudrate(M4_USART3, 115200) != Ok)
{
while(1);
}
/* Set USART RX IRQ */
stcIrqRegiCfg.enIRQn = Int000_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartRxIrqCallback;
stcIrqRegiCfg.enIntSrc = INT_USART3_RI;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART RX error IRQ */
stcIrqRegiCfg.enIRQn = Int001_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartErrIrqCallback;
stcIrqRegiCfg.enIntSrc = INT_USART3_EI;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/*Enable RX && RX interupt && TX function*/
USART_FuncCmd(M4_USART3, UsartRx, Enable);
USART_FuncCmd(M4_USART3, UsartRxInt, Enable);
USART_FuncCmd(M4_USART3, UsartTx, Enable);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
int fputc(int ch, FILE *f)
{
USART_SendData(M4_USART3, (uint8_t)ch);
while(Reset == USART_GetStatus(M4_USART3, UsartTxEmpty));
return ch;
}
通过上面的程序,我们可以看到在接收中断函数中,接收到的数据又通过printf函数再次打印出来,printf函数是通过USART发送功能重载fputc这个函数来实现的, 运行结果如下图所示:
我们在控制LED闪烁的时候使用了Ddl_Delay1ms这个函数,这个是在ddl.config.h文件中通过配置DDL_UTILITY_ENABLE宏为DDL_ON才可以使用的;在使能DDL_UTILITY_ENABLE这个宏之后,在hc32f46x_utility.h 文件中默认定义了UART_DEBUG_PRINTF这个宏,所以导致在我们重载fputc这个函数的时候会报错,所以我样在hc32f46x_utility.h文件中把这个宏注释掉就可以了。
2.移植SHELL
下载SHELL开源源代码:https://github.com/NevermindZZT/letter-shell,最新的版本是3.0的,程序中使用的是2.x的版本;在官网上有详细的功能、移植、配置,以及相应的应用说明,大家可以去深入了解,我们这边还是结合HC32F460来实现应用移植;在工程中添加letter shell 2.x的源文件,添加自定义的shell_port.c和shell_port.h这两个文件,将之前的串口初始化程序移动到这个.c文件中来实现;移植过程如下:
这样我们最单的SHELL框架就移植完成了;尝试编译运行一下,如下图所示:
具体的代码实现可以参考最后的附件工程源代码部分。
3.SHELL控制
结合上篇的LED闪烁的实验,我们通过调用SHELL自定义的命令来控制LED闪烁的起停动作,具体实现如下程序:
/* Private variables ---------------------------------------------------------*/
uint8_t LED_ToggleEnable = 1;
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LED_Toggle(void)
{
if(LED_ToggleEnable)
{
LED0_TOGGLE(); Ddl_Delay1ms(100);
LED1_TOGGLE(); Ddl_Delay1ms(100);
LED2_TOGGLE(); Ddl_Delay1ms(100);
LED3_TOGGLE(); Ddl_Delay1ms(100);
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LED_StartToggle(void)
{
LED_ToggleEnable = 1;
}
SHELL_EXPORT_CMD(start, LED_StartToggle, led start toggle);
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LED_StopToggle(void)
{
LED_ToggleEnable = 0;
}
SHELL_EXPORT_CMD(stop, LED_StopToggle, led stop toggle);
4.运行结果
5.工程源代码
本帖最后由 xld0932 于 2021-4-8 23:32 编辑
厉害了!还没尝试过shell的移植,有机会试一下!!!感谢分享!