• [问题求助] 【求助】LiteOS在GDF303CET6 MCU上,概率性发生任务调度异常问题
    类似的问题在3月份的时候也发生过,当时柴工帮忙定位liteOS不支持中断嵌套,systick_handler中增加了锁保护,问题解决,详见帖子:https://bbs.huaweicloud.com/forum/thread-47283-1-1.html但是,最近发现又出现这种情况了,问题描述:MCU有两路slave I2C,分别对接带内和带外通信,在带内和带外同时访问的场景下,任务调度又发生了异常,表现就是消息处理任务得不到调度,消息不处理。在发生问题后调用LOS_QueueInfoGet接口将队列的状态打印出来,发现和之前的问题类似:没有读任务去处理消息队列。目前这两路I2C已经设置不同的响应优先级,不会被嵌套,所以百思不得其解,请各位大佬提供下定位思路,感谢!
  • [技术干货] 详解智能建筑消防预警系统设计与实现
    主要内容项目场景说明 火焰传感器介绍 红外接收管 项目实现一、项目场景高层建筑越来越多,高楼大厦的消防隐患就更加严峻,加之目前的消防救援车辆对高层的火灾救援仍旧没有很好的解决方案,因此大楼在发生火灾后通常只能等待大火燃尽熄灭,造成的经济损失,社会影响都比较严重。为了避免此类问题的发生,大楼的消防预警系统就成为了现代高楼设计的重中之重。二、任务目标        某百层以上的摩天大楼即将完工,为提高大楼的安全性需要对大楼的消防设施进行配套。为配合喷淋及大楼报警装置的使用,需要使用火焰传感器对大楼内的明火进行提前预警。请使用火焰传感器对明火信号进行监测,并将监测结果发送至上位等待对明火的进一步处理。三、火焰传感器介绍        火焰是由各种燃烧生成物、中间物、高温气体、碳氢物质以及无机物质为主体的高温固体微粒构成的。火焰的热辐射具有离散光谱的气体辐射和连续光谱的固体辐射。         火焰传感器检测火焰主要依靠光谱中的特征波长的光线。火焰传感器类型        火焰传感器检测火焰主要依靠光谱中的特征波长的光线,根据不同特征的光线可将火焰传感器分为远红外火焰传感器和紫外火焰传感器。红外接收管        火焰传感器之所以能够检测火焰接受到红外信号的原因是由于使用红外接收头做为火焰传感器的眼睛。常见的940nm红外接收管如图。         远红外火焰传感器可以用来探测火源或其它一些波长在700纳米~1100纳米范围内的热源。红外接收管的特征与原理        红外线接收管是将红外线光信号变成电信号的半导体器件,它的核心部件是一个特殊材料的PN结,和普通二极管相比,在结构上采取了大的改变,红外线接收管为了更多更大面积的接受入射光线,PN结面积尽量做的比较大,电极面积尽量减小,而且PN结的结深很浅,一般小于1微米。        红外线接收二极管是在反向电压作用之下工作的。没有光照时,反向电流很小(一般小于0.1微安),称为暗电流。当有红外线光照时,携带能量的红外线光子进入PN结后,把能量传给共价键上的束缚电子,使部分电子挣脱共价键,从而产生电子——空穴对(简称:光生载流子)。四、项目分析        本项目设计中通过940nm的红外接收管经过运算放大器采集火焰红外信息,并将采集信息打印在PC上,定时进行更新,硬件结构主要由STM32F407、火焰传感器、串口和LCD屏幕组成。五、项目硬件图        火焰传感器原理图六、火焰传感器程序逻辑七、项目实现主函数模块/********************************************************************************************** 头文件*********************************************************************************************/#include "stm32f4xx.h"#include "delay.h"#include "led.h"#include "key.h"#include "lcd.h"#include "usart.h"#include "Flame.h"/********************************************************************************************** 名称:main()* 功能:火焰传感器驱动逻辑代码* 参数:无* 返回:无* 修改:*********************************************************************************************/void main(void){  unsigned char led_status = 0;                                //存储火焰状态变量  delay_init(168);                                              //延时初始化  led_init();                                                   //初始化LED控制管脚  key_init();                                                   //初始化按键检测管脚  lcd_init(FLAME1);                                             //LCD初始化  usart_init(115200);                                           //串口初始化  flame_init();                                                 //火焰传感器初始化    while(1){                                                     //循环体    if(get_flame_status() == 1){                                //检测到火焰      led_status = ~led_status;                                 //LED灯的状态反转                 printf("fire!\r\n");                                      //串口打印提示信息      //LCD更新数据      LCDDrawFnt16(4+30,30+20*7,4,320,"  检测到火焰",0x0000,0xffff);    }    else{                                                       //没有检测到火焰      led_status = 0;                                           //熄灭LED灯      printf("no fire!\r\n");                                   //串口打印提示信息      //LCD更新数据      LCDDrawFnt16(4+30,30+20*7,4,320,"未检测到火焰",0x0000,0xffff);    }    if(led_status == 0)                                         //根据LED灯的状态控制LED灯的变化      led_control(0);                                           //关闭LED灯    else      led_control(D3|D4);                                       //点亮LED灯    delay_ms(1000);                                             //延时1秒  }}  火焰传感器初始化void flame_init(void){    GPIO_InitTypeDef GPIO_InitStructure;                  //定义一个GPIO_InitTypeDef类型的结构体    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //开启火焰相关的GPIO外设时钟    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;            //选择要控制的GPIO引脚    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        //设置引脚的输出类型为推挽    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;          //设置引脚模式为输入模式    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;        //设置引脚为下拉模式    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;      //设置引脚速率为2MHz    GPIO_Init(GPIOB, &GPIO_InitStructure);                //初始化GPIO配置}获取火焰传感器状态unsigned char get_flame_status(void){    if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10))        return 1;    else        return 0;}八、项目思考火焰传感器检测火焰信号的原理是什么? 火焰传感器在工业上有哪些应用?LiteOS操作系统如何移植进项目?项目如何对接华为云平台?注:参考项目,记得在评论区回复:拯救小白       关于项目思考的问题,大家可以在评论区积极讨论!!!说不定会有额外大奖哦!
  • [问题求助] 关于LiteOS发送PWM的问题
    请问LiteOS有没有发送PWM脉冲信号的函数呢,华为有没有这方面的教程或者demo实例?
  • [问题求助] LiteOs当前有支持mips芯片的demo吗?
    如题,装备在mips芯片上运行LiteOs,想了解一下当前有支持mips芯片的demo开发板可以参考吗?
  • [技术干货] LiteOS大揭秘【02】:你一定不知道,LiteOS竟偷偷隐藏了这些调测功能
    【摘要】 本文主要介绍了LiteOS的调测功能,重点介绍了其中的异常接管和CPU占用率查看功能 作为物联网应用开发者,以上场景是不是很熟悉。日常开发工作中,难免会碰到bug导致系统异常崩溃/卡死的情况。踩内存、死锁、内存泄漏……开发中总会有各种坑等着你。在不额外增加打印、不用gdb单步调试等情况下,有没有什么方法能定位出问题原因?为帮助开发者找到bug原因,LiteOS提供了一系列的调测功能,比如异常接管、临终遗言。异常接管异常接管作为一种调测手段,可以在串口上输出异常发生时的日志,包括异常类型、寄存器信息、栈回溯信息(可以得到函数调用过程)、异常时正在执行的任务信息(如任务名、任务号、栈大小)、所有未退出的任务信息(包括任务名、任务号、栈大小、状态等)、内存信息等。用户可以根据寄存器内容,追溯函数间的调用关系,再辅以任务信息和内存信息,定位分析问题。通过地址越界写,构造的异常打印如下:CPU占用率考虑到有些异常情况下,可能不会触发上面的系统异常处理流程,比如系统运行卡顿,LiteOS提供了查看CPU占用率的功能。LiteOS的CPU占用率,采用任务记录的方式。在任务切换时,记录任务启动时间和切出时间;任务切出或者退出时间,系统还会累加整个任务的占用时间。CPU占用率分为系统CPU占用率和任务CPU占用率两种。系统CPU占用率 = 系统中除空闲任务外其他任务运行总时间 / 系统运行总时间。系统CPU占用率用于表示系统一段时间内的闲忙程度,也表示CPU的负载情况。任务CPU占用率 = 任务运行总时间 / 系统运行总时间。任务CPU占用率用于表示单个任务在一段时间内的闲忙程度。用户通过系统和各个任务的CPU占用率,可以找到导致系统卡顿的某个或某几个任务,同时也能据此判断任务的设计是否符合预期。相关代码在kernel/extended/cpup/目录下,下面是LiteOS中看到的CPU占用率效果图: LiteOS的调测百宝箱,针对踩内存、内存泄漏、野指针释放等问题,提供了一系列的内存调测能力;针对互斥锁死锁问题,提供了死锁检测能力。除此之外,还有对任务、中断、队列、信号量、软件定时器等各种事件的跟踪调测功能。这些调测功能,均已安排在小编的工作日程中,不久后小编就会陆续揭开它们的神秘面纱,希望能给开发者带来更多帮助和支持。
  • [技术干货] LiteOS大揭秘【01】:5分钟带你了解LiteOS传感框架
    LiteOS传感框架是什么LiteOS传感框架即Sensor Hub,是一个基于Huawei LiteOS物联网操作系统的传感器管理框架。随着物联网的发展,物联网终端越来越智能化,例如在个人穿戴、智能家居、家用医疗等终端上将配置越来越多的传感器,来获取更多传感数据,使终端更加智能,使得开发和维护变得复杂和困难。LiteOS传感框架将物联网终端设备上例如加速计(Accelerometer)、陀螺仪(Gyroscope)、气压仪(Barometer)、温湿度计(Humidometer)等不同类型的传感器统一管理,通过抽象不同类型传感器接口,屏蔽其硬件细节,做到“硬件”无关性,非常方便于物联网设备的开发、维护和功能扩展。 LiteOS传感框架架构介绍LiteOS传感框架主要包括了Sensor Manager、BSP manager,Converged Algorithms。Sensor Manager:统一的传感器交互管理,如Sensor的配置、采样、上报和管理。BSP Manager:统一的驱动接口,负责Sensor驱动管理、电源管理、Sensor交互管理,如Sensor的打开、关闭、读写、数据更新等。Converged Algorithms:融合算法库(算法基于具体的业务模型),根据具体业务模型,在端侧MCU进行算法融合,例如环境监测算法、计步算法等,从传统、简单采集算法升级到智能算法,应用直接调用,提升传感数据的业务精准度,降低数据采集时延。 LiteOS传感框架特点提升开发效率,降低开发难度LiteOS传感框架实现对物联网终端Sensor的统一管理,对不同类型传感器进行抽象,软件工程师专注于功能开发,硬件工程师专注于底层驱动适配,开发人员不需要懂软件又懂硬件,降低了开发难度,提升了开发效率。软件架构分层分级,方便功能扩展和维护由于软件架构分层,非常方便于物联网设备日后的维护和扩展升级。 LiteOS传感框架适用的场景LiteOS传感框架是LiteOS物联网操作系统的Sensor管理框架,适应于多种物联网终端的开发。对于智能化、低功耗、多种Sensor、产品更新迭代快的终端设备,更能体现出传感框架的优势,例如可穿戴设备、智能家居设备、家用医疗设备等等。例如在运动手表(手环)中,就有心率测量(PPG)、环境光、加速度计、磁力计、气压计、GPS等多种传感器,数据上报频繁复杂,不同传感器数据需要协同运算处理,对数据采集、传输、处理提出了更高的要求,同时设计通用的软件平台、提升续航指标也面临巨大挑战。使用SensorHub传感框架有效解决了通用性问题。另外统一的传感器周期管理,还有效减少了无用的中断唤醒,再结合LiteOS出色的低功耗管理能力,助力产品快速上市,具有很好的竞争力。
  • [技术干货] LiteOS大揭秘系列
    【01】5分钟带你了解LiteOS传感框架https://bbs.huaweicloud.com/forum/thread-61132-1-1.html【02】你一定不知道,LiteOS竟偷偷隐藏了这些调测功能https://bbs.huaweicloud.com/forum/thread-61133-1-1.html【03】LiteOS可移植性探究https://bbs.huaweicloud.com/forum/thread-65163-1-1.html【04】当LiteOS遇上Mindspore,为物联网插上AI的翅膀https://bbs.huaweicloud.com/forum/thread-84579-1-1.html【05】LiteOS形式化验证,为物联网硬件安全保驾护航https://bbs.huaweicloud.com/forum/thread-84582-1-1.html【06】零成本学习LiteOS快速入门https://support.huaweicloud.com/qs-LiteOS/zh-cn_topic_0308937187.html【07】使用LiteOS Studio揭秘LiteOS在STM32上如何运行https://bbs.huaweicloud.com/forum/thread-94234-1-1.html【08】LiteOS Studio图形化调测能力,物联网打工人必备https://bbs.huaweicloud.com/forum/thread-95330-1-1.html【09】使用LiteOS Studio镜像分析工具评估优化LiteOS镜像https://bbs.huaweicloud.com/forum/thread-95327-1-1.html【10】LiteOS调测利器之backtrace原理剖析https://bbs.huaweicloud.com/forum/thread-106185-1-1.html
  • [技术干货] 0x08 LiteOS_Lab仓库组件详解 cJSON(下)
    三、cJson库中封装相关函数详解假设我们收到了一帧JSON格式来自服务器的数据,如下图:           从JSON的字面意思可以理解:该数据是一个命令,命令的键为“Light”,值为“ON”,命令单片机将板载LED灯打开。我们可以这样理解这个数据,”paras”、”service_id”和”command_name”都术语同一个object中的item,我们暂时可以忽略”paras”和”service_id”参数,先提取paras这个object类型的item,然后读取”paras”中的item的键是否包含”Light”,如果包含再读取”Light”键对应的值为ON还是OFF。       具体步骤可以分为:①    将MQTT接收任务中收到的“string“类型的数据转换为JSON格式②    读取object中的paras项目,并查询其中是否有特定名称的键(Light)③    提取特定名称键的值④    根据②、③步骤中获取的键、值来执行相应操作⑤    上报处理结果将MQTT接收任务中收到的数据解析为JSON格式首先创建一个cJSON类型的结构体指针,用于保存将MQTT接收任务中收到的“string“类型的数据转换为JSON格式的数据调用CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);函数,传入MQTT接收任务中收到的“string“类型的数据指针,解析完成之后可以收到一个cJSON类型的结构体指针,使用完之后记得释放,否则会造成内存泄漏。从object中读取item       将解析出来的JSON结构体指针传入作为第一个参数,”paras”作为第二个参数传入CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);函数,将得到一个cJSON类型的结构体指针,该指针的内容就是名为”paras”的item。       将名为”paras”的item cJSON结构体指针作为第一个参数,“Light”作为第二个参数传入CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);函数,如果paras中包含名为”Light”的item,则会放回true,这是我们可以通过if语句进行判断,如果存在,则进行读取名为”Light”的键对应的值。从object中读取值       将指向名为”Light”的item的cJSON函数指针传入CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);即可在函数返回值得到一个字符串指针,我们可以通过strstr等等之类的字符串比较函数判断该返回值是否为”ON”或者”OFF”,并指示单片机完成相应操作即可。 总结以及注意事项:cJSON库的操作到这里就大概说完了,大家还可以自行查阅cJSON.h文件,里面定义了很多函数和结构体,可以根据自己需要进行的操作调用相应的函数来处理,唯一需要注意的是无论是创建Object还是解析string,用完之后一定要记得释放内存,如果使用了例如将JSON格式的数据生成为非格式化字符串的函数一定要记得释放这个string字符串指针对的的内存,否则最终会造成内存泄露,导致程序出错。
  • [技术干货] 0x07 LiteOS内核详解--中断接管机制(下)
    三、中断接管机制涉及到的文件los_hwi.c文件解析       该函数的本质就是直接通过C语言中嵌入汇编代码,读取IPSR寄存器的值,__get_IPSR()函数声明如下图:IPSR寄存器的解析----转自M3内核手册这些函数是用于处理系统中断,系统中断并未被LiteOS中断管理器接管,而是采用传统方案,当发生中断后,直接由中断向量表跳转过来执行。       除系统中断以外的全部中断发生后,都是先跳转到osInterrupt()中执行。①    先保存PRIMASK的值,然后关闭全部可屏蔽中断,相当于进入临界区。②    恢复PRIMASK的值,相当于进入退出区。③    获取当前触发的中断号④    计算出当前中断的对应处理函数在存储初段处理函数的数组中的位置⑤    如果该位置有处理函数就开始调用处理函数来处理中断⑥    调用处理函数来处理中断⑦    如果没有处理函数的中断发生了,就执行LiteOS默认的中断处理函数,其作用就是打印当前发生中断的值。⑧    先保存PRIMASK的值,然后关闭全部可屏蔽中断,相当于进入临界区。⑨    恢复PRIMASK的值,相当于进入退出区。g_vuwIntCount这个值用于表示当前程序的状态,是否处于中断(异常)状态,如果处于异常状态有些操作不能进行,例如:获取互斥锁,调用系统延时函数等等,防止在中断处理中出现死锁的情况,导致一直无法退出中断。       还有一个问题需要注意:中断标志位的清除,因为由用户自己写在用户的中断处理函数中,LiteOS并未帮我们提供。       LiteOS通过将“中断处理函数指针”按照中断向量表中要求的顺序装入一个函数指针数组中,并通过链接脚本放置到向量表处(也就是0x8000_0000的地方),图中①处就是叫链接器将这块数组数据放到.isr_vector的地方。       到这里相信细心的同学一定发现了只有14个函数指针+一个栈顶地址,stm32中那么多的中断,14个函数指针怎么会够用?       现在就可以引出另外一个中断相关的文件----__vectors.h文件,②处在预处理时就会将该文件的内容替换到#incldue “__vectors.h”处。我这里只截取了该文件的部分代码,因为太多了,并且都是一样的,到底要在我们的中断向量表中添加多少个函数指针,取决于系统默认定义的OS_HWI_MAX_NUM宏,在Cortex-m3,Cortex-m4 和 Cortex-m7中该宏的为240,一般情况下用户不需要自己修改,使用默认的即可,因为最大中断数和CPU有着强相关。       初始化硬件中断,根据芯片内核来设置向量表偏移量寄存器,用于重定位中断向量,如果芯片是M3、M4等大于M3的内核还需要设置中断优先级组,默认是7。该函数用于创建LiteOS的中断,最终被osal_int_connect函数调用。uwHwiNum中断号(stm32xxx.h文件中有定义,例如USART1_IRQn)。usHwiPrio中断优先级(这是LiteOS接管中断后的优先级,后面也会设置为NVIC中的优先级)。usMode该参数暂时未被使用。pfnHandler中断处理函数的函数指针。uwArg假设我们的中断处理函数具有参数,可以通过该参数传入。该函数首先判断我们传入的参数是否处于合理的范围,如果都正确,就关闭所有中断,将我们填入的参数存储到m_pstHwiSlaveForm结构体数组中,并使能我们传入的中断和设置NVIC中该中断的优先级,最后开启恢复所有中断并返回OK。中断删除函数,本质上就是关闭该中断,并将该终端的信息从m_pstHwiSlaveForm结构体数组中移除即可。 与中断接管机制相关的文件和函数大概都介绍完了,大家如果有不明白的地方欢迎留言,我会给大家解答。四、中断向量表是如何被链接到”0”地址处__attribute__关键字       attribute有属性的含义,一般出现在代码中是用来定义“编译属性”的,当我们需要将C语言代码中的某个部分编译后链接到某个特定的段时,就需要在这个部分前面加上__attribute__((section(段名))),例如在LiteOS代码中使用了__attribute__ ((section(".isr_vector")))将实现的中断向量表数组设置为.isr_vector段的位置,等待链接器链接到.isr_vector段中。       因为中断向量表数组在los_hwi.c文件中,所以我们可以反汇编编译los_hwi.c后生成的los_hwi.o中间文件来一探究竟。       使用反汇编命令 arm-none-eabi-objdump -x -j.isr_vector。-x选项用于显示数据段的全部信息,如果不加该选项则看不到完整的数据。--j.isr_vector选项用于反汇编指定的段,我们只关心.isr_vector段。结果如下:              编译器将下图的这部分数组相关代码编译到了.isr_vector段中:·偏移量完全和中断向量表中要求的移植,等到链接时,就会将该段的内容(也就是这个数组中的内容)链接到.isr_vector处,下图为链接脚本(os.ld文件):这段数据被放到了0x8000_0000处,上电后stm32“硬件上”自动将0x0000_0000地址和0x8000_0000地址处关联,通俗的来说就是STM32访问0x0000_0000处的数据,实际**问到了0x8000_0000处的数据,也就读取到了栈顶地址、中断向量表。总结:中断向量表为什么会被链接到”0”地址处(这里的0是指0x8000_0000),一个是加载地址,一个是运行时地址。这里的“链接”比较片面,还包括了编译器进行编译时,将存放中断向量表的数据标记为了.isr_vector段,当链接器来链接生成elf文件时,将.isr_vector段内的数据放到了0x8000_0000地址处(加载时地址)。五、中断接管机制的好处       我们可以对比不采用中断接管的方式和采用了中断接管机制的方式实现的中断处理,采用了中断接管的方式:1、 可以实现中断统一管理,如果要使用某个中断,直接调用osal_int_connect函数创建该中断,并将中断处理函数指针与之绑定,中断处理函数的名称完全可以自定义,无需像之前一样必须按照系统要求设定。2、 便于移植,移植的时候无需考虑下层代码,因为不同芯片中断处理相关部分的差异完全被中断接管部分屏蔽。3、 便于维护,调用删除中断函数,即可马上删除某个中断。其他好处就不一一列举了。 
  • [技术干货] LiteOS中的LOS_TASK_CB结构体的认识和理解
           在嵌入式系统开发中,在没有操作系统的裸机程序一般只有一个任务,即从main开始的无限循环的程序。而有了操作系统之后,嵌入式系统就可以实现多个任务的运行,这可以极大的提高嵌入式系统的软件功能。通常,实现多任务的运行管理功能是一个操作系统的核心功能。Lite OS也一样。在Lite OS 的任务运行和管理功能中,有个非常重要的结构体LOS_TASK_CB,称为任务控制块。每个任务都有一个属于自己的任务块实例。这个任务控制块中包含了该任务的很多信息。正确的理解和分析这个结构体成员变量的含义,有助于理解Lite OS中的任务相关的概念,有助于用好Lite OS系统。如下图是LOS_TASK_CB的定义,它总共有19个成员变量。       1. void *pStackPointer: 栈指针,指向任务栈空间的指针。      每一个任务都拥有一个独立的栈空间。任务栈空间,就是系统为这个任务在内存里面分配的一块存储区域,在这个存储区域里面存放的这个任务相关的局部变量、寄存器、函数参数、函数返回地址等。         当系统中有多个任务运行时,可能发生任务的切换。即暂停某个任务的运行(即某一个任务被阻塞了),而让另外一个任务运行(即另外一个任务进入运行状态)。当发生任务切换时,会将暂停运行的任务的上下文信息保存在自身的任务栈空间里面,以便任务恢复时还原现场,从而在任务恢复后在切出点继续开始执行。      在用户创建自己的任务的时候,需要设定好任务栈空间的大小。任务栈空间的大小设置多少比较合适,即不浪费内存够,也不至于发生栈溢出的问题?这个暂时没看到更具体的说明,或者计算方法。       2.UINT16 usTaskStatus:表示任务的状态。      通常在理论分析或者设计的时候,会说Lite OS 中的任务通常有四种状态,即就绪(Ready),运行(Running),阻塞(Blocked),退出态(Dead)。在程序中有如下宏定义来表示一个任务或者任务块的更加具体的状态。#define OS_TASK_STATUS_UNUSED                       0x0001#define OS_TASK_STATUS_SUSPEND                      0x0002#define OS_TASK_STATUS_READY                        0x0004#define OS_TASK_STATUS_PEND                         0x0008#define OS_TASK_STATUS_RUNNING                      0x0010#define OS_TASK_STATUS_DELAY                        0x0020#define OS_TASK_STATUS_TIMEOUT                      0x0040#define OS_TASK_STATUS_EVENT                        0x0400#define OS_TASK_STATUS_EVENT_READ                   0x0800#define OS_TASK_STATUS_SWTMR_WAIT                   0x1000#define OS_TASK_STATUS_PEND_QUEUE                   0x2000#define OS_TASK_STATUS_PEND_MUT                     0x4000#define OS_TASK_STATUS_PEND_SEM                     0x8000这些状态的意义可以根据宏定义的名称略知一二,在程序源码中也有更详细的说明,在这里就不在赘述了。      3. UINT32 usPriority: 任务的优先级。数值越大,代表优先级越低。多个处在就绪状态的任务,要执行的时候,优先级高的任务将被优先执行。      4. UINT32 uwStackSize: 任务栈空间的大小。在创建任务的时候,可以通过设置这个成员变量,来指定任务栈空间的大小。在程序中,有两个相关宏定义,如下。       #define OS_TASK_PRIORITY_HIGHEST                    0       #define OS_TASK_PRIORITY_LOWEST                     31       从这两个宏定义可以看出,Lite OS 中任务的最高优先级是0,最低优先级是31,总共有32个优先级。     5. UINT32 uwTopOfStack: 任务栈的栈顶。如下简单示意了,在任务栈空间中栈顶,栈底,栈指针的相对位置关系。通常栈顶所指向的是栈空间中内存地址最小的单元。uwTopOfStack + uwStackSize = uwBottomOfStack。这里的uwBottomOfStack指向的是栈底,在TSK_INFO_S结构体中有使用它。      6. UINT32 uwTaskID: 任务的编号。系统中可以运行多个任务,给每个任务一个编号,便于任务管理。任务的编号,Lite OS 系统内核初始化的时候,已经根据配置的最大任务数量,为每个任务配置了任务编号。见如下程序段中的513行。      7. TSK_ENTRY_FUNC pfnTaskEntry: 任务的入口函数。每个新任务得到调度后将执行的函数。该函数由用户实现,在任务创建时,通过任务创建结构体指定。      这个入口函数跟没有操作系统的嵌入式C程序中的main函数有点相似。如果将main函数看成一个任务,那么在具有多个任务的操作系统中,需要给每个任务指定它的入口函数,就像是指定了多个main函数一样。      8. void *pTaskSem: 与任务相关的信号量。      9. void *pTaskMux: 与任务相关的互斥量      10. UINT32 uwArg: 任务相关的参数。通常用来当做入口函数的参数。类似一些C/C++程序中带参数的main函数的参数,例如void main(int argc,char *argv[])中的argc,argv[ ]参数。     11. char *pcTaskName: 任务的名字。用户自己定义,名字的含义有助于理解这个任务的功能。     12. LOS_DL_LIST  stPendList: 引起这个任务挂起的对象列表。引起该任务挂起的对象,会由系统统一调度和管理。     13. LOS_DL_LIST  stTimerList:  与这个任务相关的定时器列表。由用户     14. UINT32 uwIdxRollNum: 与任务调度运行相关的变量。     15. EVENT_CB_S uwEvent: 与任务相关的事件控制块变量。     16. UINT32 uwEventMask: 事件的掩码     17. UINT32 uwEventMode: 事件的模式     18. void  *puwMsg:   指向队列存储区域的指针     19. struct _reent  stNewLibReent: 新库的_reent结构体变量。        从第8-第19个成员变量,用户在使用过程中用的比较少,更多用于系统内部功能实现。与之相关的信号量、互斥量、事件、队列等在LiteOS的开发说明中有相关的更详细的内容。以上仅仅是个人的一些理解和认识,有不正确或者不全的欢迎大家指出和补充,分享学习,共同进步。
  • [技术干货] 0x07 LiteOS_Lab仓库组件详解 cJSON(上)
    摘要:我们将设备采集到的数据上传到云平台一般有两种主流的方式:二进制码流和json,本章用于讲解在LiteOS仓库中集成的cJson库,用于将需要上报的数据封装为json格式或者将云平台下发的json格式数据解析出来。一、华为云平台需要的json数据格式当我们下位机使用mqtt协议来进行通讯并且mcu的ram和flash也比较充裕,我们就可以采用json格式来和云平台进行数据交互。首先在定义产品的时候协议类型选择MQTT和数据格式选择JSON:大家可以查看下这个帮助手册,主要说明了华为云平台要求的JSON数据格式的要求,JSON数据格式分为设备命令、设备消息和设备属性,我这里主要说的是设备属性和设备命令:设备属性上报、设备命令下发。services:类型为list(array),存放设备服务数据service_id:类型为string,与我们产品中的服务相对应Agricultureproperties:类型为object,存放设备服务的属性,例如Temperature、Humidity等,和属性名称及值对应,在产品中定义的,如下图。云平台收到的数据必须与我们在产品中定义的数据格式相同,必选的属性必须存在,否则该数据会被丢弃,如果收到的数据正确我们就可以在“设备”页面中看到如下显示:二、cJSON库简介到这里大家应该明白了为什么今天我们需要讲解cJson库了,cJson库的作用是什么了。cJSON库是一个基于MIT的代码,项目仓库地址:https://github.com/DaveGamble/cJSON,我们在LiteOS中主要用到其中的两个文件:cJSON.h和cJSON.c。该库可以十分方便的将我们的数据结构体,例如:转换为json格式的,甚至还能直接以非格式化字符的形式打印出来,就是这样的:,极大的提高了我们处理数据的效率,还能将json格式的数据转换为便于处理的键、值等等。三、cJson库中封装相关函数详解这里就以上面的Agriculture的上报属性数据的结构体为例,带领大家将它转换为JSON格式的数据。几个重要概念       Object和Item:Object和Item是相对的,不是绝对的,这句话有些抽象,我来举个例子向大家说明,例如之前我的定义的json数据:1、 ①到⑩之间的所有数据可以称为一个Object,②到⑩之间的数据就是它的键为”services”,类型为array的item。2、 ②到⑩之间的所有数据可以称为一个Object,其中③处的键值对是它的第一个键为“service_id”,类型为string的item,其中④到⑨处的键值对是它的第二个键为“properties”,类型为Object的item。3、 ④到⑧之间的所有数据可以称为一个Object,其中⑤⑥⑦都是分别是该Object的三个item,他们的类型都是int。        嵌套:嵌套的意思大家只要理解了上面我说的Object和Item的概念就算理解了。Object中嵌套了Object,那这个被嵌套的Object就是Item。cJSON结构体       该结构体的声明在cJSON.h文件中,大家可以自行查看。next和prev指针:通过cJSON结构体定义的变量可以实现一个链表,在进行增、删、查、改时通过next和prev指针来完成。child指针:当我们需要添加一个item到某个Object的时候(嵌套),就将这个item指针挂接到该节点的child成员上。type变量:用于标记该item的类型,例如string、number、bool、array、object等。valuestring指针:用于当item类型为string类型时,指向值所对应的字符串。valueint变量:用于当item类型为number类型时,存储值对应的int类型数据。Valuedouble变量:用于当item类型为number类型时,存储值对应的double类型数据。string指针:指向该item键的对应的名称。当该item为bool类型,其中的值为false或者true时,该值存储于type变量处。绑定系统特有的内存分配及释放函数       因为在创建object和删除object时需要使用到内存,所以在初始化cJSON库时,我们就需要将系统中进行内存分配及释放的函数注册到cJSON库中。例如裸机开发时,用malloc分配内存,用free释放内存。例如用LiteOS_Lab框架开发时,用osal_malloc分配内存,用osal_free释放内存。通过如下操作即可完成注册:Object的创建我们需要进行json格式数据处理时,首先通过JSON数据类型定义一个JSON数据类型变量指针,并通过cJSON_CreateObject为其分配内存并初始化(如果是array类型的object则调用cJSON_CreateArray,其他类型的创建可以自己类比,创建相关函数见下图)。向Object中添加item例如我们要创建如下的一个JSON格式的数据。首先需要创建两个Object,第一个称为root的Object,后面将键为properties的item挂上去,第二个为properties的Object,用于“温度、湿度、光照”键值对的挂接。代码部分:unsigned char* str_js = NULL;            //定义一个字符串指针cJSON* cjson_root = NULL;               //定义cJSON类型的指针cJSON* cjson_properties = NULL; cjson_root = cJSON_CreateObject();  //为上面的指针分配内存并进行初始化cjson_properties = cJSON_CreateObject(); //将温度、湿度、光照键值对添加到名为properties的Object中cJSON_AddNumberToObject(cjson_properties, "Temperature", 20);cJSON_AddNumberToObject(cjson_properties, "Humidity", 18);cJSON_AddNumberToObject(cjson_properties, "luminance", 50); //将名为cjson_data的Object挂接到名为cjson_root的Object上cJSON_AddItemToObject(cjson_root, "properties", cjson_properties); //将cJSON转换为非格式化字符串打印一下str_json = cJSON_Print(cjson_root);printf("Data is %s\r\n", str_json); //用完之后一定要记得释放cJSON_Delete(cjson_root);if(str_json!=NULL)osal_free(str_json); 效果图如下: PS:关于指令的解析放在下一篇来说!
  • [技术干货] 浅析LiteOS启动过程-基于STM32L431
    摘要:本文简要的分析了基于STM32L431的智慧农业案例程序中的LiteOS的启动过程。从经典的main函数开始,到LiteOS正常启动,实现任务的调度。通过这种分析,可以很好的理解LiteOS的一些运行原理过程,有助于LiteOS移植过程中的问题排查,有助于在其他芯片上顺利移植LiteOS。1.从主函数main()进入在嵌入式C语言程序中,程序通常从main函数开始执行。在没有操作系统的时候,通常在主程序中会有一个无限循环。例如下面的这一段程序。在无限循环中,不断控制两个LED灯的亮灭控制。但是,当程序有了操作系统后,这个主函数还有吗?这个无限循环还会有吗,它的运行逻辑是什么?   下面是智慧农业的程序的main函数在这个main函数中62行,调用Hardware_Init进行硬件初始化。主要是时钟、GPIO、UART、LCD等的初始配置。63行,调用LOS_Kernelinit( )对Lite OS的内核进行初始化。70行,调用create_work_tasks(void) 创建了一个工作任务。77行,调用LOS_Start( )启动LiteOS系统。可以看出,在上面的程序中,没有出现while(1)这样的无限循环。那么77行,调用LOS_Start()后,接下来的要执行的程序代码去哪里了?难道就这样return0了吗?不应该。从哪里消失,从哪里找起。从LOS_Start( )“消失”,继续从LOS_Start( )看起。2. 进入LOS_Start( )LOS_Start( )函数在los_init.c文件中,代码如下在99行,调用osTickStart(); 配置Lite OS系统的时钟。Lite OS系统的时钟配置和刚开始的时钟的初始化配置不同。刚开始的时钟配置是基于STM32L431的系统进行的时钟配置。这里的时钟配置,是Lite OS系统中时钟配置。这里Lite OS系统时钟,类似于大家常用的桌面操作系统的时钟概念。   在121行,调用LOS_StartToRun( );启动Lite OS 运行。 LOS_StartToRun()函数,在Keil 环境中,通过右键->转到定义 的方法,找不到函数的实现文件。通过在整个项目中,查找LOS_StartToRun发现LOS原来的los_dispatch_keil.S文件中。3. 进入los_dispatch_keil.S los_dispatch_keil.S使用汇编语言编写的,主要实现了下面几个重要的函数及全局变量。其中有LOS_StartToRun 函数。这个LOS_StartToRun函数就应该是在LOS_Start()函数最后调用的那个LOS_StartToRun( )。 LOS_StartToRun函数代码如下这个代码用汇编语言写的。很难看懂,但是76-80行的注释,简要的说明了这个函数的调用形式以及功能:这个函数是没有返回值,没有参数的,它主要实现了 启动第一个任务,这个任务具有最高的优先级。其他的任务都是由任务调度来启动。任务调度在哪里?下面一会会说。这个函数中最后一行 BX R6 上面的注释说,直接跳转到了g_stLosTask.pstRunTask中存储的PC指针处了,这样main函数的相关新就丢失了,程序就不会返回到main函数中了。通常在嵌入式汇编程序中,调用子程序时,通常会保存号当前函数相关的信息,等调用完后,在恢复到调用的函数中。而这里的 BX R6 并没有让LOS_StartToRun函数返回到调用它的函数中,这样程序就不会在返回到main函数中了。至此,main函数结束了。整个系统的运行就全部依靠Lite OS系统了。不返回main函数了,那么程序从哪里开始执行了?从 PC of g_stLosTask.pstRunTask,开始执行了。这里的PC是程序计数器,里面存储着CPU下一次要执行的程序指令的地址。执行完BX R6后,CPU就取到了g_stLosTask.pstRunTask地址中存储的指令,开始执行了。这个g_stLosTask.pstRunTask里面存储的是什么?在整个项目中查找g_stLosTask.pstRunTask,发现有如下代码在osTaskInit()函数中,对g_stLosTask.pstRunTask进行了赋值。从分析赋值过程语句,可发现在g_stLosTask.pstRunTask中存储了要执行的任务相关的信息存储在里面了,即任务控制块(task control block structure即LOS_TASK_CB中的内容)的内容存储在g_stLosTask.pstRunTask中了。在汇编语言中,将g_stLosTask.pstRunTask中的相关信息存储到STM32L431的相关的工作寄存器中,例如R6 工作寄存器。这样程序就可以执行任务了。而任务的相关信息、入口函数等都可以用C语言来编写。至此,程序可以绕道执行任务相关的代码了。“绕道”,这里绕道可以理解为,终于绕开了那个main函数了,可以执行操作系统中的多个任务了!多个任务的调度,主要由LOS_IntLock,LOS_IntUnlock,LOS_IntRestore,osTaskScheldule,PendSV_Handler这些函数实现。这些函数也是用汇编语言写的。那么这里可以看出,针对不同芯片移植LiteOS的时候,由于不同的汇编语言可能需要不同的类似los_dipatch_keil.S这样的汇编语言编写程序文件。4.综述通过以上的分析,可以看出,在Lite OS在启动的时候,是从main函数中被调用开始,而在被调用的过程中,没有让PC指针再次跳转回main函数中,而是直接跳转到执行任务的命令的地址上去,从而开启了具有多任务执行能力的操作系统功能。
  • [问题求助] LiteOS最新版本移植问题
    Gitee上的LiteOS最新版本与原LiteOS在目录结构上存在较多差异,但是官方给出的移植指南未进行更新,造成像我这样的初学者难以快速开展移植工作,官方能否进行更新,指导初学者快速入门。
  • [问题求助] 根据官方《Huawei LiteOS 开发指南》中第一例之“任务创建”出错
        今天将LiteOS移植到了stm32f103rct6开发板上,学习《Huawei LiteOS 开发指南》中的《任务》一节,输入所给代码(https://gitee.com/LiteOS/LiteOS/blob/master/doc/Huawei_LiteOS_Developer_Guide_zh.md#%E7%BC%96%E7%A8%8B%E7%A4%BA%E4%BE%8B )到新创建的test_task.c中,在main函数中调用函数Example_TskCaseEntry_Another(),输出有错误提示:[ERR] CURRENT task ID: 6 stack overflow!(具体请看图)     图1 main函数中调用图2 输出结果    本人是新手不清楚问题出在哪里,请问大家是我在los_config.h中配置出错了吗?还是有其他的问题呢?代码放到附件中了,麻烦大家帮忙解决一下,谢谢了!
  • [问题求助] LiteOS 内核测试工具
    RT求问,LiteOS有自动的内核测试工具吗?例如 syzkaller 之类的。
总条数:623 到第
上滑加载中