功能简介:
有点类似shell指令一样,Linux下的shell是通过输入指令,然后shell脚本去按path路径去寻找相应指令,运行最先找到的那个指令文件。这里实现的机制则是通过串口输入指令,单片串口接受并分析指令,然后匹配对应的指令然后运行并反馈。到这里,这个程序倒是开拓了我的思路,以前没想过使用串口来控制单片机的,最多就是收发一些字符串。由于原子哥的视频长度有限,也可能是他们不想在语法上花费过多时间,所以讲解的就比较的简略,下面我将根据其运行的过程以及一些语法上做出一些解释。
流程分析
1.定时器中断的扫描函数

void TIM4_IRQHandler(void)
{                                   if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET)//溢出中断{usmart_dev.scan(); //执行usmart扫描    TIM_SetCounter(TIM4,0);     //清空定时器的CNTTIM_SetAutoreload(TIM4,100);//恢复原来的设置                                                            }                  TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除中断标志位
}

原子哥在视频中说过这个的实现过程是通过定时器中断执行这个usmart的扫描函数,下面再看看扫描函数中的具体逻辑,如果在一个工程里面难以寻找到一个中断函数,可以在启动文件中寻找。

2.扫描函数

void usmart_scan(void)
{u8 sta,len;  if(USART_RX_STA&0x8000)//串口接收完成?{                     len=USART_RX_STA&0x3fff;    //得到此次接收到的数据长度USART_RX_BUF[len]='\0';    //在末尾加入结束符. sta=usmart_dev.cmd_rec(USART_RX_BUF);//得到函数各个信息if(sta==0)usmart_dev.exe();   //执行函数 else {  len=usmart_sys_cmd_exe(USART_RX_BUF);if(len!=USMART_FUNCERR)sta=len;if(sta){switch(sta){case USMART_FUNCERR:printf("函数错误!\r\n");            break;  case USMART_PARMERR:printf("参数错误!\r\n");              break;              case USMART_PARMOVER:printf("参数太多!\r\n");             break;      case USMART_NOFUNCFIND:printf("未找到匹配的函数!\r\n");               break;      }}}USART_RX_STA=0;//状态寄存器清空        }
}

USART_RX_STA是设定一个标志字节,bit7,6是判断是否接受完成并且接受数据是否正确,bit0~5则是接受的字符串长度,可以看出扫描函数的逻辑很简单就是接受数据然后判断数据,然后执行,接下来就是如何对命令进行处理以及运行命令
2.1 usmart处理串口数据

u8 usmart_cmd_rec(u8*str)
{u8 sta,i,rval;//状态  u8 rpnum,spnum;u8 rfname[MAX_FNAME_LEN];//暂存空间,用于存放接收到的函数名 ,//#define MAX_FNAME_LEN         30 u8 sfname[MAX_FNAME_LEN];//存放本地函数名sta=usmart_get_fname(str,rfname,&rpnum,&rval);//得到接收到的数据的函数名及参数个数   if(sta)return sta;//错误for(i=0;i<usmart_dev.fnum;i++){sta=usmart_get_fname((u8*)usmart_dev.funs[i].name,sfname,&spnum,&rval);//得到本地函数名及参数个数if(sta)return sta;//本地解析有误     if(usmart_strcmp(sfname,rfname)==0)//相等{if(spnum>rpnum)return USMART_PARMERR;//参数错误(输入参数比源函数参数少)usmart_dev.id=i;//记录函数ID.break;//跳出.}   }if(i==usmart_dev.fnum)return USMART_NOFUNCFIND;  //未找到匹配的函数sta=usmart_get_fparam(str,&i);                   //得到函数参数个数  if(sta)return sta;                              //返回错误usmart_dev.pnum=i;                               //参数个数记录return USMART_OK;
}

这里有函数usmart_get_fname(str,rfname,&rpnum,&rval);//得到接收到的数据的函数名及参数个数,其原形是
u8 usmart_get_fname(u8str,u8fname,u8 *pnum,u8 *rval)
这里可以是对指针的一种经典用法,传入两个字符串的地址,然后进行操作,常见一些字符串操作函数,比如大家常用strpcy()之类的,传入参数,修改参数的用法还有更多更复杂的用法,但是其核心原理就是通过指针去修改指针所指向的内存区域,指针指向谁就修改谁,n级指针修改n-1级指针的内存区域,所以遇到指针多画内存的四区模型以后可能会更新,这里挖一个小坑。下面我们先介绍一下这个函数的具体逻辑,

//从str中得到函数名 串口接受到的数据,也就是指令名
//*str:源字符串指针
//*fname:获取到的函数名字指针
//*pnum:函数的参数个数
//*rval:是否需要显示返回值(0,不需要;1,需要)
//返回值:0,成功;其他,错误代码.
u8 usmart_get_fname(u8*str,u8*fname,u8 *pnum,u8 *rval)
{u8 res;u8 fover=0;      //括号深度u8 *strtemp;u8 offset=0;  u8 parmnum=0;u8 temp=1;u8 fpname[6];//void+X+'/0'u8 fplcnt=0; //第一个参数的长度计数器u8 pcnt=0;     //参数计数器u8 nchar;//if(((pcnt&0x7f)==4)&&(*strtemp!='*'))break;//最后一个字符,必须是*//个人感觉这句话应该使用 || //if(((pcnt&0x7f)==4)||(*strtemp ='*'))break;//这样当读完五个字符或者最后一个读是‘*’ 表示指针才算是把参数类型读完整了/*****************************///判断函数是否有返回值strtemp=str;while(*strtemp!='\0')//没有结束{if(*strtemp!=' '&&(pcnt&0X7F)<5)//最多记录5个字符{  if(pcnt==0)pcnt|=0X80;//置位最高位,标记开始接收返回值类型if(((pcnt&0x7f)==4)&&(*strtemp!='*'))break;//最后一个字符,必须是*fpname[pcnt&0x7f]=*strtemp;//记录函数的返回值类型pcnt++;}else if(pcnt==0X85)break;strtemp++; } if(pcnt)//接收完了{fpname[pcnt&0x7f]='\0';//加入结束符if(usmart_strcmp(fpname,"void")==0)*rval=0;//不需要返回值else *rval=1;                            //需要返回值pcnt=0;} /*****************************///这一块就很简单了,就是跳过空格,不要被循环条件所迷惑了,主要就是跳过所有空格和'*' 主要看offset的值,他会是函数名的前一个位置res=0;strtemp=str;while(*strtemp!='('&&*strtemp!='\0') //此代码找到函数名的真正起始位置{  strtemp++;res++;if(*strtemp==' '||*strtemp=='*'){nchar=usmart_search_nextc(strtemp);      //获取下一个字符if(nchar!='('&&nchar!='*')offset=res;   //跳过空格和*号}}  /*****************************/strtemp=str;if(offset)strtemp+=offset+1;//跳到函数名开始的地方       res=0;nchar=0;//是否正在字符串里面的标志,0,不在字符串;1,在字符串;while(1){if(*strtemp==0){res=USMART_FUNCERR;//函数错误break;}else if(*strtemp=='('&&nchar==0)fover++;//括号深度增加一级    else if(*strtemp==')'&&nchar==0){if(fover)fover--;else res=USMART_FUNCERR;//错误结束,没收到'('if(fover==0)break;//到末尾了,退出      }else if(*strtemp=='"')nchar=!nchar;//根据括号判断函数名是否接受完,一个字符一个字符的传递if(fover==0)//函数名还没接收完{if(*strtemp!=' ')//空格不属于函数名{*fname=*strtemp;//得到函数名fname++;}}else //已经接受完了函数名了.{if(*strtemp==','){temp=1;      //使能增加一个参数pcnt++; }else if(*strtemp!=' '&&*strtemp!='('){if(pcnt==0&&fplcnt<5)     //当第一个参数来时,为了避免统计void类型的参数,必须做判断.{fpname[fplcnt]=*strtemp;//记录参数特征.fplcnt++;}temp++;   //得到有效参数(非空格)}if(fover==1&&temp==2)//temp {temp++;        //防止重复增加parmnum++;    //参数增加一个}}strtemp++;          }   if(parmnum==1)//只有1个参数.{fpname[fplcnt]='\0';//加入结束符if(usmart_strcmp(fpname,"void")==0)parmnum=0;//参数为void,表示没有参数.}*pnum=parmnum; //记录参数个数*fname='\0'; //加入结束符return res;      //返回执行结果
}

重点先记住几个参数的意义,

关于正点原子USMART的一些理解相关推荐

  1. 正点原子USMART组件移植

    文章目录 一.打开Cube,建立工程 二.系统配置 三.配置测试IO 四.在 Clock Configuration中: 五.工程输出配置 六.开始移植 七.组件分析 MCU:正点原子阿波罗开发板 I ...

  2. 正点原子USMART使用

    USMART是正点原子开发的stm32调试工具,可以通过串口调用相应函数并执行. 1.USMART组件移植 USMART组件共五个文件分别为 usmart.c---------负责与外部互交等 usm ...

  3. 正点原子USMART 调试组件实验学习笔记(一)

    目录 1.简介 2.USMART 组件的移植 1.简介 USMART 是由 ALIENTEK 开发的一个灵巧的串口调试互交组件,通过它你可以通过串口 助手调用程序里面的任何函数,并执行.因此,你可以随 ...

  4. 正点原子USMART调试学习笔记(二)

    软件设计 keilkill.bat,是一个批处理文件,双击,可以删除 MDK 编译过程中产生的中间文件, 从而大大减少整个工程所占用的空间,节省硬盘空间,方便传输. 由于 USMART 默认提供了 S ...

  5. STM32 USMART源码理解

    本文是基于正点原子USMART源码理解. 该组件由 ALIENTEK 开发提供,功能类似 linux 的 shell(RTT 的 finsh 也属于此类).USMART 最主要 的功能就是通过串口调用 ...

  6. dev c++怎么调试_「正点原子NANO STM32开发板资料连载」第十八章 USMART 调试组件...

    1)实验平台:ALIENTEK NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第十八章 U ...

  7. 【正点原子STM32连载】 第二十六章 USMART调试组件实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1

    1)实验平台:正点原子MiniPro H750开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560 3)全套实验源码+手册+视频 ...

  8. 正点原子 在ADC实验中添加USMART,通过串口查看电压值

    结合了实验十七和实验十四.由于没有买LCD的板子,所以通过串口调试来查看电压值. 目录 一.准备工作:头文件 二.添加一些代码 三.开始调试 一.准备工作:头文件 1.首先将实验十四的USMART文件 ...

  9. 正点原子中 IIC 例程中SDA_IN()和SDA_OUT()函数理解

    在学习正点原子IIC例程时遇到SDA_IN()和SDA_OUT()两个端口模式配置函数,代码如下: //IO口方向设置 #define SDA_IN() {GPIOB->MODER&=~ ...

最新文章

  1. 海尔、南方电网:这个AI引擎,装它!
  2. centos 6 上安装l7 filter尝试过滤xunlei
  3. 三大工厂模式的优缺点
  4. php+tp框架+API,【路由】利用Thinkphp路由实现API开发版本管理
  5. 【离散数学】树的基本概念和结论
  6. java代码的接口_Java代码--简单接口的实现
  7. Docker学习总结(50)——Docker 微服务优雅关闭
  8. 数字游戏---巧妙解答
  9. MyDAL - is null is not null 条件 使用
  10. Ansible--常用模块
  11. Spring 菜鸟教程 异常 集锦
  12. 计算机的用户账户,计算机用户名是什么意思(如何修改和设置用户名)
  13. 科学网肖波:海外博后申请的一点经验与看法
  14. 2012中国互联网公司、全球互联网公司最新市值排名(2012.12.06)
  15. win7的计算机功能在那打开,win7系统照相机功能在哪?win7系统打开照相机功能的方法...
  16. 全国大学生“高教杯”成图大赛——图错了如何修改
  17. 热爱可抵岁月漫长,温柔可挡艰难时光—2020年终总结
  18. 智慧水务信息化平台建设,实现供水一体化管控
  19. 应用统计学考研要考计算机,应用统计专业考研经验贴
  20. 半衰期用能量宽度来表示

热门文章

  1. 性价比超高,铁威马F4-423(4G)正式上线!
  2. php 随机三位数字,PHP实现生成随机码
  3. 如何修改用户下的文件夹名,保姆级教程
  4. wangEditor使用教程
  5. Vulnhub-vulncms
  6. 从一场相亲说起,决策树
  7. 流量卡办理:流量卡激活需要多长时间,关于流量卡激活问题汇总!
  8. python wav文件音频频谱图音量分析,静音截取
  9. linux(文件、文件夹的复制与移动)
  10. MegaCli 工具安装使用