出出啊
出出啊
It is Not the Mountain We Conquer, but Ourselves

注册于 6 months ago

回答
902
文章
19
关注者
55

那个vs编译器的判断...
可能曾经有人想移植到win上用vs编译,然后模拟器启动,之后就没之后了。
使用nano版本要极其小心初始化顺序。其实,标准版本里也有这种让人迷惑的行为。初始化串口过程中就有调用 rt_kprintf 的可能
没有把控制台串口清晰,无任何系统依赖的进行初始化配置。这一点儿,让初始接触 rtt 框架学习者摸不着头脑

inline 分两种,一种是在头文件定义的,一种是源码文件内部定义的。或者说一种是全局inline 一种是局部inline(这些不是专业说法,专业说法请百度)。
但是,针对后一种,必须定义为static inline。前一种必须在头文件里定义声明。
高版本编译器也可能没有这个问题,但是上面的用法还是遵循比较好,兼容性高。

  1. 152 行的 rt_device_write(serial, 0, CO2_TxBuffer, sizeof(CO2_TxBuffer)); 这句,可以放到 send_thread_entry 线程入口函数 while 循环之前。
  2. recieve_thread_entry 线程和 uart_input 这个中断回调函数之间进行通信,使用邮箱传递 size 值就好(不传递也没问题),接收线程收到 uart_input 发的信号后,进行 rt_device_read 。
  3. 鉴于你使用的这种设备,它每包数据长度应该是固定的,是固定字节数的。每次 rt_device_read 返回的 rx_length 并不一定是完整包长度值。因此,rx_buffer[rx_length] = '\0'; 这个操作是很危险的,可能破坏数据。—— 你说的接收两次数据,可能是因为这里引起的。

中断回调函数 uart_input 可以给 recieve_thread_entry 发信号量。接收线程每次执行 rt_device_read 的时候需要判断返回值够不够你想要的数据量。如果不够,继续 rt_device_read。如果超了,需要取出你需要的个数的数据,进行解析处理。剩下的仍然留在你的应用缓冲区内,等待下次信号。

接收完成 rt_device_write(serial, 0, rx_buffer, rx_length); 回传操作是设备要求的吗?

接收完成给发送线程发事件通知它发读取命令。从这里看,这俩线程完全可以合并成一个线程。
发请求,等待中断回调函数里的信号,读取数据,解析数据,延时,发下一次请求。。。。。。

项目目录下,Debug Release 文件夹内有各自的 makefile

硬件定时器的回调函数在中断里被调用执行的。记住这一点儿就够了。
所有的中断,无论是在 rtos 系统里还是裸机里,行为模式是一样的。都是直接抢 CPU 资源,其它的代码执行被暂停。
这种暂停不是线程暂停,是意外抢夺了 cpu。对于线程来说,就像是一场梦。中断的时候肯定不会执行任何线程的代码。这个时候线程可以是任何状态,运行中的线程仍然是运行态

把启动注册调用的函数改成全局函数接口,程序里调用
但是有个问题,多数只有注册,没有卸载的过程。需要自己实现卸载,切换的时候先卸载前一种再注册成新的
理论上是可以的,实际操作也没有多少难点儿。

当我的网络接口重新建立后,MQTT任务就正常了,恢复正常运行。

这里其实是重新配置网卡了吧。感觉像是底层驱动出问题了。协议栈不应该出现这种情况。

lwip 有 2.1.2 了。中间有什么 bug 更新也难说,试过新版本啥样没?

线程被信号量挂起,然后变成僵尸线程的情况有很多人遇到过。一直没有人讲清楚原因来。

  1. 512 堆栈很紧张
  2. th1 = rt_thread_create("th1", th1_entry,RT_NULL,512, 21, 0); 0 时间片。这个操作很秀啊。
  3. 典型的内存被污染了。导致程序运行不正常。目测这里没有非法写的代码。项目中其它地方可能有bug
  4. 刚发现,rt_mq_create("mq1", 10, sizeof(MYMSG), RT_IPC_FLAG_FIFO); 这个用法是错的!!! 第二个参数是消息体大小,第二个参数是消息队列中最大消息数量。

意外掉电,文件写入的时候出错了吧
不是掉电就是驱动,或者硬件问题了。

  1. systick 定时间隔是一个时间片的时基。
  2. 作为一个可抢占式嵌入式系统内核,每个线程有预先设定的时间片参数,这个在 rt_thread_create rt_thread_init 函数里有体现。
  3. 当一个线程出现长时间占用 CPU 的需求时,会根据它占用 CPU 的时间片来决定是不是要剥夺它的 CPU 使用权。当且仅当有更高优先级线程就绪,此线程时间片耗尽的时候才会发生线程调度,切换到高优先级线程上。同优先级线程也会切换。

线程的时间片单位应该是tick数,不应该等同于ms。systick 定时 10ms 的时候,一个tick的时间是10ms。5tick=50ms。
你说的假设二可能想表达的是 5tick。这个假设的理解是对的。

判断优先级进行调度的函数 rt_schedule 。看到 scheduler.c 文件就应该想到在这个文件里。

finsh 组件里有个源码文件 cmd.c 。这个没参与编译。
添加这个文件就行了。

这个芯片不能用 keil 开发吗?
env + keil 灵活性很高的,studio 就比较受限制。

不得说一句,这两天论坛前端程序员搞的这个行内代码样式很丑,上面还有白底灰字的段代码样式。

EfErrCode ef_set_env(const char *key, const char *value)
{
    return ef_set_env_blob(key, value, strlen(value));
}

看这个就明白了吧,第二个参数是字符串,第三个参数是字符串长度。
如果用 ef_set_env 函数,少写一个参数;如果用 ef_set_env_blob 自己指定长度,这种情况下,第二个参数不一定是字符串了,可以是任意内存地址,第三个参数就是内存数据字节个数。

对于整型变量,要么转成字符串;要么使用

ef_set_env_blob(key, &value, sizeof(int));

找到这个 timer 是干啥的,删掉
没猜错的话,是检测连 internet 网络状态的。可以看看我的文章怎么裁剪 lwip

回到
顶部

发布
问题

投诉
建议