对于做linux开发的研发人员来说,大家都喜欢通过输入指令符来执行一些命令操作,如果在MCU编程过程中有一个类似linux的shell命令工具可以通过串口调试助手输入命令然后运行一些调试函数,将会为编程提供极大的帮助。
对于MCU来说,每次修改程序调试就需要重新下载,有时候仅仅是调试修改几个参数,这样反复修改程序编译下载就显得很繁琐,浪费时间,而且在调试电机、电源等高压电源类应用时,如果出现操作错误,有可能会造成炸机毁坏电脑等危险,如果有一个类似linux的命令行操作,这样就可以省出很多时间,但是由于MCU存储资源和运算速度等限制,所以想实现一个同样功能的操作,就需要做一些处理优化。
目前有很多类似的shell代码,本次介绍如何在MM32MCU上使用shell来辅助开发,由于篇幅过长,所以将分三个章节讲述实现方式,本章节将教大家基础的软件配置,后面章节将带领大家学习如何配置JlinkRTT和shell的程序配置。硬件资源如下:本次实验将在基于MM32L073的MiniBoard上进行测试验证,实现shell的通信端口可以使用任意通信方式,如UART、USB、SPI、IIC、485等方式,本次使用MM32L073PF的UART1作为shell输入输出通道,
如图2。PA15作为状态指示LED1的控制引脚,如图3。
图1串口硬件原理图
图2LED硬件原理图软件资源如下:结合上述使用到的硬件资源,下面我们着重介绍软件实现流程以及相关配置代码,主要涉及如何移植shell的输入输出以及如何执行命令。
以下为主函数初始化配置及相关全局变量定义内容,代码如下:
//>>>状态指示LED1的初始化配置>>>
voidLED_Init(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
RCC_AHBPeriphclockCmd(RCC_AHBPeriph_GPIOA,ENABLE);//开启GPIOA时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
LED1_OFF();
}
voiduart_nvic_init(u32bound)
{
//>>>GPIO端口设置>>>
GPIO_InitTypeDefGPIO_InitStructure;
UART_InitTypeDefUART_InitStructure;
NVIC_InitTypeDefNVIC_InitStructure;
//>>>使能外设时钟>>>
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1,ENABLE);//使能UART1
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);//开启GPIOA时钟
//>>>UART1NVIC配置>>>
NVIC_InitStructure.NVIC_IRQChannel=UART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority=3;//子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化NVIC寄存器
//>>>UART的GPIO复用功能配置>>>
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);
//>>>UART初始化设置>>>
UART_InitStructure.UART_BaudRate=bound;//串口波特率
UART_InitStructure.UART_WordLength=UART_WordLength_8b;//字长为8位数据格式
UART_InitStructure.UART_StopBits=UART_StopBits_1;//一个停止位
UART_InitStructure.UART_Parity=UART_Parity_No;//无奇偶校验位
UART_InitStructure.UART_HardwareFlowControl=UART_HardwareFlowControl_None;//无硬件数据流控制
UART_InitStructure.UART_Mode=UART_Mode_Rx|UART_Mode_Tx;//收发模式
UART_Init(UART1,&UART_InitStructure);//初始化串口1
UART_ITConfig(UART1,UART_IT_RXIEN,ENABLE);//开启串口接受中断
UART_Cmd(UART1,ENABLE);//使能串口1
//>>>UART1_TXGPIOA.9>>>UART1_RXGPIOA.10>>>
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//PA.9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA.9
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOAtiNG;//浮空输入
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA.10
}
//>>>UART发送一个字节>>>
voidUart_PutChar(charchByte)
{
while((UART1->CSR&UART_IT_TXIEN)==0);
UART1->TDR=(chByte&(uint16_t)0x00FF);
}
//>>>UART发送字符串>>>
voidUart_PutBuff(uint8_t*pchBuff,uint32_twLen)
{
while(wLen--){
Uart_PutChar(*pchBuff);
pchBuff++;
}
}
//>>>main主函数>>>
intmain(void)
{
delay_init();
LED_Init();
uart_nvic_init(115200);//串口初始化为115200
//uart_shell.read=shellRead;
uart_shell.write=Uart_PutChar;
shellInit(&uart_shell);//shell初始化
while(1)
{
}
}
移植的步骤先定义一个shell对象,即:SHELL_TypeDefuart_shell;
然后实例化对象的操作接口,对于本次我们采用中断接收,所以不用调用读取接口函数,所以接收接口如下修改:
//uart_shell.read=shellRead;注释掉读取接口,采用中断处理代码如下:
voidUART1_IRQHandler(void)//串口1中断服务程序
{
u8Res;
IF(UART_GeTITStatus(UART1,UART_IT_RXIEN)!=RESET){
UART_ClearITPendingBit(UART1,UART_IT_RXIEN);
Res=UART_ReceiveData(UART1);//读取接收到的数据
shellHandler(&uart_shell,Res);//shell处理函数
}
}
然后实例化发送接口,代码如下:uart_shell.write=Uart_PutChar;
最后实例化对象,代码如下:shellInit(&uart_shell);
完成shell对象的全部实例化,那么我们如何加入我们需要的命令函数呢?很简单,有多种方式,本次我们介绍最简单的一个,即SHELL_EXPORT_CMD();其它参考源码,本次我们加入测试代码如下:
voidled1_on(void)
{
LED1_ON();
}
SHELL_EXPORT_CMD(led1_on,led1_on,led1_on);//三个变量:命令,功能,描述
voidled1_off(void)
{
LED1_OFF();
}
SHELL_EXPORT_CMD(led1_off,led1_off,led1_off);//同上
voidled1_toggle(void)
{
LED1_TOGGLE();
}
SHELL_EXPORT_CMD(led1_toggle,led1_toggle,led1_toggle);
voidreboot(void)
{
NVIC_SystemReset();
}
SHELL_EXPORT_CMD(reboot,reboot,reboot);
如上完成所有代码后下载烧写进入,然后打开PuTTY,设置为115200,界面如下:
图3命令列表选择输入对应的指令命令,MCU执行对应的指令操作;比如输入led1_on即可打开led1,输入led1_off关闭led1,输入led1_toggle反转led1亮灭,输入reboot则MCU重启,输入cls清除当前窗口。
图4控制LED1亮
本次实验的的外设配置及操作如上所述,在下一章节将带领大家学习shell的程序和JlinkRTT的配置等。