Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
红外_IR_infrared
基于rt-thread的多通道红外nec接收框架
发布于 2022-02-21 11:46:48 浏览:1017
订阅该版
[tocm] ** ** ### 多通道红外驱动接收框架😎😎 ** **### 最下面有阅读建议和增加通道的步骤方法** ** - drv_infrared.c 红外驱动文件 ``` /*我这里的四个通红通道叫左,右,左前,右前,如果需要增加的话可以自行添加*/ static struct infrared_class *infrared_left; static struct infrared_class *infrared_right; static struct infrared_class *infrared_left_front; static struct infrared_class *infrared_right_front; /* 这里可以自己添加引脚,注意要在receive init中进行初始化*/ #define IR_LEFT_RECEIVE_PIN 41 /* receive pin */ #define IR_RIGHT_RECEIVE_PIN 40 /* receive pin */ #define IR_LEFT_FRONT_RECEIVE_PIN 39 /* receive pin */ #define IR_RIGHT_FRONT_RECEIVE_PIN 38 /* receive pin */ #define RECEIVE_HWTIMER INFRARED_RECEIVE_HWTIMER /* Timer name */ #define RECEIVE_HWTIMEER_SEC 0 #define RECEIVE_HWTIMEER_USEC 100 // one decode time cnt 100us #define INFRARED_ONETBIT_TIMEOUT 500 //500 *100 = 50ms /*引脚下降沿中断服务函数,如果未开始接收,则初始化解码器,并且判断是否需要打开定时,如果正在接收中,则将下降沿之间的100us个数传递给解码器*/ static void left_receive_pin_callback(void* param) { rt_hwtimerval_t receive_time; /*judeg infrared channel is recving*/ if(receive_flag & (1 << left_index)) { infrared_left->decoder.ops->decode((struct decoder_class *)&infrared_left->decoder,infrared_left->decode_time); } else /*start timer*/ { if(!receive_flag) { receive_flag |= 1 << left_index; receive_time.sec = RECEIVE_HWTIMEER_SEC; receive_time.usec = RECEIVE_HWTIMEER_USEC; rt_device_write(receive_time_dev, 0, &receive_time, sizeof(receive_time)); } receive_flag |= 1 << left_index; /*init decoder time and stat*/ infrared_left->decode_time = 0; infrared_left->decoder.decode_cnt = 0; infrared_left->decoder.nec_state = START_STA; } } /*第二个引脚*/ static void right_receive_pin_callback(void* param) { rt_hwtimerval_t receive_time; /*judeg infrared channel is recving*/ if(receive_flag & (1 << right_index)) { infrared_right->decoder.ops->decode((struct decoder_class *)&infrared_right->decoder,infrared_right->decode_time); } else /*start timer*/ { if(!receive_flag) { receive_flag |= 1 << right_index; receive_time.sec = RECEIVE_HWTIMEER_SEC; receive_time.usec = RECEIVE_HWTIMEER_USEC; rt_device_write(receive_time_dev, 0, &receive_time, sizeof(receive_time)); } receive_flag |= 1 << right_index; /*init decoder time and stat*/ infrared_right->decode_time = 0; infrared_right->decoder.decode_cnt = 0; infrared_right->decoder.nec_state = START_STA; } } /*第三个引脚*/ ... /*第四个引脚*/ ... /*100us 超时函数,检查是否存在某个通道正在接收,如果有,通道计时增加,否则判断超时时间是否到达。如果所有通道都不在接收,则关闭定时器*/ static rt_err_t receive_timeout_callback(rt_device_t dev, rt_size_t size) { struct infrared_class *infrared; /*check if infrared recv time out*/ for(rt_uint8_t i = 0; i < ir_num; i++) { if(receive_flag & (rt_uint32_t)(0x00000001 << i)) { infrared = infrared_find((infrared_enum)i); /*one bit decode time count and time out*/ ++infrared->decode_time; if(infrared->decode_time > INFRARED_ONETBIT_TIMEOUT) { infrared->decoder.nec_state = START_STA; infrared->decode_time = 0; //infrared->decode_over_time = 0; receive_flag &= ~(rt_uint32_t)(0x00000001 << i); } } // no infrared channel recving then stop channel if(!receive_flag) { rt_device_control(receive_time_dev, HWTIMER_CTRL_STOP, RT_NULL); } return 0; } rt_err_t infrared_receive_init(void) { rt_err_t ret = RT_EOK; rt_hwtimer_mode_t mode; rt_uint32_t freq = 1000000; //1us 1Mhz //pin init rt_pin_mode(IR_LEFT_RECEIVE_PIN,PIN_MODE_INPUT_PULLUP); rt_pin_mode(IR_RIGHT_RECEIVE_PIN,PIN_MODE_INPUT_PULLUP); rt_pin_mode(IR_LEFT_FRONT_RECEIVE_PIN,PIN_MODE_INPUT_PULLUP); rt_pin_mode(IR_RIGHT_FRONT_RECEIVE_PIN,PIN_MODE_INPUT_PULLUP); rt_pin_attach_irq(IR_LEFT_RECEIVE_PIN,PIN_IRQ_MODE_FALLING,left_receive_pin_callback,RT_NULL); rt_pin_attach_irq(IR_RIGHT_RECEIVE_PIN,PIN_IRQ_MODE_FALLING,right_receive_pin_callback,RT_NULL); rt_pin_attach_irq(IR_LEFT_FRONT_RECEIVE_PIN,PIN_IRQ_MODE_FALLING,left_front_receive_pin_callback,RT_NULL); rt_pin_attach_irq(IR_RIGHT_FRONT_RECEIVE_PIN,PIN_IRQ_MODE_FALLING,right_front_receive_pin_callback,RT_NULL); rt_pin_irq_enable(IR_LEFT_RECEIVE_PIN,PIN_IRQ_ENABLE); rt_pin_irq_enable(IR_RIGHT_RECEIVE_PIN,PIN_IRQ_ENABLE); rt_pin_irq_enable(IR_LEFT_FRONT_RECEIVE_PIN,PIN_IRQ_ENABLE); rt_pin_irq_enable(IR_RIGHT_FRONT_RECEIVE_PIN,PIN_IRQ_ENABLE); receive_time_dev = rt_device_find(RECEIVE_HWTIMER); if (receive_time_dev == RT_NULL) { return RT_ERROR; } ret = rt_device_open(receive_time_dev, RT_DEVICE_OFLAG_RDWR); if (ret != RT_EOK) { LOG_E("open %s device failed!\n", RECEIVE_HWTIMER); return ret; } rt_device_set_rx_indicate(receive_time_dev,receive_timeout_callback); ret = rt_device_control(receive_time_dev, HWTIMER_CTRL_FREQ_SET, &freq); if (ret != RT_EOK) { LOG_E("set frequency failed! ret is :%d", ret); return ret; } mode = HWTIMER_MODE_PERIOD; ret = rt_device_control(receive_time_dev, HWTIMER_CTRL_MODE_SET, &mode); if (ret != RT_EOK) { LOG_E("set mode failed! ret is :%d", ret); return ret; } return ret; } //在启动函数中初始化接收相关硬件资源 int drv_infrared_init() { rt_err_t res = RT_EOK; infrared_left = infrared_find(left_index); res = infrared_init(infrared_left); infrared_right = infrared_find(right_index); res = infrared_init(infrared_right); infrared_left_front = infrared_find(left_front_index); res = infrared_init(infrared_left_front); infrared_right_front = infrared_find(right_front_index); res = infrared_init(infrared_right_front); if(res < 0) { rt_kprintf("infrared init fail!\r\n"); return -1; } #ifdef INFRARED_SEND infrared_send_init(); infrared->send = infrared_send; #endif /* INFRARED_SEND */ #ifdef INFRARED_RECEIVE infrared_receive_init(); #endif /* INFRARED_RECEIVE */ return 0; } INIT_APP_EXPORT(drv_infrared_init); ``` - infrared.h ``` #define MAX_SIZE 5 #define INFRARED_BUFF_SIZE 200 /*muti*/ typedef enum { left_index = 0, right_index, left_front_index, right_front_index, ir_num, }infrared_enum; struct ir_raw_data { rt_uint32_t decoder_time; /*unit 100us*/ }; /*nec解码器类*/ struct decoder_class { char* name; struct decoder_ops* ops; /*nec decoder status*/ nec_sta_enum nec_state; rt_uint8_t decode_cnt; //bit num in one byte struct nec_data_struct nec_data; struct rt_ringbuffer *ringbuff; void* user_data; }; struct decoder_ops { rt_err_t (*init)(struct decoder_class *decoder); rt_err_t (*deinit)(struct decoder_class *decoder); rt_err_t (*read)(struct decoder_class *decoder,struct infrared_decoder_data* data); rt_err_t (*write)(struct decoder_class *decoder,struct infrared_decoder_data* data); rt_err_t (*decode)(struct decoder_class *decoder,rt_uint32_t decode_time); rt_err_t (*control)(struct decoder_class *decoder,int cmd, void *arg); }; /*decode time 要用volatile修饰,防止读错*/ struct infrared_class { struct decoder_class decoder; //decoder class volatile rt_uint32_t decode_time; /*one carrier wave and one idle time total*/ rt_size_t (*send)(struct ir_raw_data* data, rt_size_t size); }; /*multi infrared*/ /*decoder register*/ struct infrared_class *infrared_find(infrared_enum idx); /*init and deinit infrared class */ rt_err_t infrared_init(struct infrared_class *infrared); int infrared_deinit(struct infrared_class *infrared); /*decoder read data or write data from infrared ringbuffer*/ rt_err_t decoder_read_data(struct infrared_class *infrared,struct ir_raw_data* data); rt_err_t decoder_write_data(struct infrared_class *infrared,struct ir_raw_data* data, rt_size_t size); /*infrared read and write data*/ rt_err_t infrared_read(struct infrared_class *infrared,struct infrared_decoder_data* data); rt_err_t infrared_write(struct infrared_class *infrared, struct infrared_decoder_data* data); //start decoder init rt_err_t ir_select_decoder(struct infrared_class *infrared); ``` - infrared.c ``` /*multi infrared class 如果你需要增加新的通道,这里要对应实例化一个新的类*/ static struct infrared_class infrared_left; static struct infrared_class infrared_right; static struct infrared_class infrared_left_front; static struct infrared_class infrared_right_front; #define NEC_BUFF_SIZE 8 /* unit100us */ #define IR_DECODER_LEAD_TIMER_MAX 138 //137 * 100 = 13.7ms #define IR_DECODER_LEAD_TIMER_MIN 132 //133 * 100 = 13.3ms //average 13.5ms = 9 + 4.5 #define IR_DECODER_REPEAT_TIMER_MAX 118 //117 * 100 = 11.7ms #define IR_DECODER_REPEAT_TIMER_MIN 112 //113 * 100 = 11.3ms //average 11.5ms = 9 + 2.5 #define IR_DECODER_LOW_TIMER_MAX 13 // 13 * 100 #define IR_DECODER_LOW_TIMER_MIN 7 // 7 * 100 //actual time 1.12 ms #define IR_DECODER_HIGH_TIMER_MAX 23 // 23 * 100 #define IR_DECODER_HIGH_TIMER_MIN 17 // 17 * 100 //actual time 1.68ms + 560 us /*find infrared class according to idx*/ struct infrared_class *infrared_find(infrared_enum idx) { struct infrared_class *res = RT_NULL; switch(idx) { case left_index: res = &infrared_left; break; case right_index: res = &infrared_right; break; case left_front_index: res = &infrared_left_front; break; case right_front_index: res = &infrared_right_front; break; default: break; } return res; } //init decoder rt_err_t ir_select_decoder(struct infrared_class *infrared) { ASSERT(infrared != RT_NULL); if(infrared->decoder.ops->init) { infrared->decoder.ops->init((struct decoder_class *)&infrared->decoder); return RT_EOK; } return -RT_ERROR; } rt_err_t infrared_init(struct infrared_class *infrared) { ASSERT(infrared != RT_NULL); infrared->decode_time = 0; //infrared->decode_over_time = 0; /*clear decode time*/ return RT_EOK; } rt_err_t decoder_write_data(struct infrared_class *infrared,struct ir_raw_data* data, rt_size_t size) { infrared->send(data, size); return RT_EOK; } rt_err_t infrared_read(struct infrared_class *infrared,struct infrared_decoder_data* data) { if(infrared->decoder.ops->read) { return infrared->decoder.ops->read((struct decoder_class *)&infrared->decoder,data); } return -RT_ERROR; } rt_err_t infrared_write(struct infrared_class *infrared,struct infrared_decoder_data* data) { if(infrared->decoder.ops->write) { return infrared->decoder.ops->write((struct decoder_class *)&infrared->decoder,data); } return -RT_ERROR; } ``` - nec_decode.c ``` //init decoder mem, if mem init ok , then return ok static rt_err_t nec_decoder_init(struct decoder_class *decoder) { ASSERT(decoder != RT_NULL); if(!decoder->ringbuff) { decoder->ringbuff = rt_ringbuffer_create(sizeof(struct nec_data_struct) * NEC_BUFF_SIZE); } decoder->decode_cnt = 0; decoder->nec_state = START_STA; rt_memset(&decoder->nec_data,0,sizeof(struct nec_data_struct)); /*clear nec status and data*/ return RT_EOK; } // free decoder static rt_err_t nec_decoder_deinit(struct decoder_class *decoder) { ASSERT(decoder != RT_NULL); rt_ringbuffer_destroy(decoder->ringbuff); decoder->decode_cnt = 0; decoder->nec_state = START_STA; rt_memset(&decoder->nec_data,0,sizeof(struct nec_data_struct)); /*clear nec status and data*/ return RT_EOK; } static rt_err_t nec_decoder_control(struct decoder_class *decoder,int cmd, void *arg) { return RT_EOK; } //nec_decoder protocol static rt_err_t nec_decoder_decode(struct decoder_class *decoder,rt_uint32_t decode_time) { struct infrared_class *infrared = decoder->user_data; switch(decoder->nec_state) { case START_STA: /* judge lead code or repeat code */ { // is lead code if(decode_time >= IR_DECODER_LEAD_TIMER_MIN && decode_time <= IR_DECODER_LEAD_TIMER_MAX) { decoder->nec_state = LEAD_CODE_STA; decoder->decode_cnt = 0; decoder->nec_data.repeat = 0; } // is repeat code else if(decode_time >= IR_DECODER_REPEAT_TIMER_MIN && decode_time <= IR_DECODER_REPEAT_TIMER_MAX) { decoder->nec_state = START_STA; //return to sta repeat+ decoder->nec_data.repeat++; rt_ringbuffer_put(decoder->ringbuff, (rt_uint8_t *)&(decoder->nec_data), sizeof(struct nec_data_struct)); } else { decoder->nec_state = START_STA; } infrared->decode_time = 0; //clear decode time for next decode } break; case LEAD_CODE_STA: { if(decode_time >= IR_DECODER_HIGH_TIMER_MIN && decode_time <= IR_DECODER_HIGH_TIMER_MAX) /* bit 1 */ { decoder->nec_data.custom1 >>= 1; decoder->nec_data.custom1 |= 0x80; decoder->decode_cnt++; } else if(decode_time >= IR_DECODER_LOW_TIMER_MIN && decode_time <= IR_DECODER_LOW_TIMER_MAX) /*bit 0*/ { decoder->nec_data.custom1 >>= 1; decoder->nec_data.custom1 |= 0x00; decoder->decode_cnt++; } else /* time no match */ { decoder->decode_cnt = 0; decoder->nec_state = START_STA; } infrared->decode_time = 0; //clear decode time for next if(decoder->decode_cnt >= 8) // bit num 8 reach { decoder->nec_state = CUSTOM_CODE1_STA; decoder->decode_cnt = 0; } } break; case REPEAT_STA: { } break; case CUSTOM_CODE1_STA: { if(decode_time >= IR_DECODER_HIGH_TIMER_MIN && decode_time <= IR_DECODER_HIGH_TIMER_MAX) /* bit 1 */ { decoder->nec_data.custom2 >>= 1; decoder->nec_data.custom2 |= 0x80; decoder->decode_cnt++; } else if(decode_time >= IR_DECODER_LOW_TIMER_MIN && decode_time <= IR_DECODER_LOW_TIMER_MAX) /*bit 0*/ { decoder->nec_data.custom2 >>= 1; decoder->nec_data.custom2 |= 0x00; decoder->decode_cnt++; } else /* time no match */ { decoder->decode_cnt = 0; decoder->nec_state = START_STA; } infrared->decode_time = 0; //clear decode time for next if(decoder->decode_cnt >= 8) // bit num 8 reach { decoder->nec_state = CUSTOM_CODE2_STA; decoder->decode_cnt = 0; } } break; case CUSTOM_CODE2_STA: { if(decode_time >= IR_DECODER_HIGH_TIMER_MIN && decode_time <= IR_DECODER_HIGH_TIMER_MAX) /* bit 1 */ { decoder->nec_data.key1 >>= 1; decoder->nec_data.key1 |= 0x80; decoder->decode_cnt++; } else if(decode_time >= IR_DECODER_LOW_TIMER_MIN && decode_time <= IR_DECODER_LOW_TIMER_MAX) /*bit 0*/ { decoder->nec_data.key1 >>= 1; decoder->nec_data.key1 |= 0x00; decoder->decode_cnt++; } else /* time no match */ { decoder->decode_cnt = 0; decoder->nec_state = START_STA; } infrared->decode_time = 0; //clear decode time for next if(decoder->decode_cnt >= 8) // bit num 8 reach { decoder->nec_state = DATA_CODE1_STA; decoder->decode_cnt = 0; } } break; case DATA_CODE1_STA: { if(decode_time >= IR_DECODER_HIGH_TIMER_MIN && decode_time <= IR_DECODER_HIGH_TIMER_MAX) /* bit 1 */ { decoder->nec_data.key2 >>= 1; decoder->nec_data.key2 |= 0x80; decoder->decode_cnt++; } else if(decode_time >= IR_DECODER_LOW_TIMER_MIN && decode_time <= IR_DECODER_LOW_TIMER_MAX) /*bit 0*/ { decoder->nec_data.key2 >>= 1; decoder->nec_data.key2 |= 0x00; decoder->decode_cnt++; } else /* time no match */ { decoder->decode_cnt = 0; decoder->nec_state = START_STA; } infrared->decode_time = 0; //clear decode time for next if(decoder->decode_cnt >= 8) // bit num 8 reach { decoder->nec_state = START_STA; // when key2 receive decoder->decode_cnt = 0; rt_ringbuffer_put(decoder->ringbuff, (rt_uint8_t *)&(decoder->nec_data), sizeof(struct nec_data_struct)); } } break; case DATA_CODE2_STA: // stop bit ignore ( for there is no falling level to check ) { } break; default: break; } return RT_EOK; } static struct decoder_ops ops; int nec_decoder_register() { struct infrared_class *infrared; ops.control = nec_decoder_control; ops.decode = nec_decoder_decode; ops.init = nec_decoder_init; ops.deinit = nec_decoder_deinit; ops.read = nec_decoder_read; ops.write = nec_decoder_write; infrared = infrared_find(left_index); infrared->decoder.name = "nec_left"; infrared->decoder.ops = &ops; infrared->decoder.user_data = infrared; infrared = infrared_find(right_index); infrared->decoder.name = "nec_right"; infrared->decoder.ops = &ops; infrared->decoder.user_data = infrared; infrared = infrared_find(left_front_index); infrared->decoder.name = "nec_left_front"; infrared->decoder.ops = &ops; infrared->decoder.user_data = infrared; infrared = infrared_find(right_front_index); infrared->decoder.name = "nec_right_front"; infrared->decoder.ops = &ops; infrared->decoder.user_data = infrared; return 0; } INIT_PREV_EXPORT(nec_decoder_register); ``` - decode.h ``` typedef enum { START_STA = 0, LEAD_CODE_STA, CUSTOM_CODE1_STA, CUSTOM_CODE2_STA, DATA_CODE1_STA, DATA_CODE2_STA, REPEAT_STA, }nec_sta_enum; struct nec_data_struct { rt_uint8_t custom1; rt_uint8_t custom2; rt_uint8_t key1; rt_uint8_t key2; rt_uint8_t repeat; }; struct infrared_decoder_data { union { struct nec_data_struct nec; }data; }; ``` - main.c ``` infrared_left = infrared_find(left_index); infrared_right = infrared_find(right_index); infrared_left_front = infrared_find(left_front_index); infrared_right_front = infrared_find(right_front_index); ir_select_decoder(infrared_left); ir_select_decoder(infrared_right); ir_select_decoder(infrared_left_front); ir_select_decoder(infrared_right_front); while(1) { if(infrared_read(infrared_left,&infrared_left_data) == RT_EOK) { if(infrared_left_data.data.nec.repeat) { rt_kprintf("left repeat%d\n", infrared_left_data.data.nec.repeat); } else { rt_kprintf("left custom1:0x%02X custom2:0x%02X key1:0x%02X key2:0x%02X\n",infrared_left_data.data.nec.custom1,infrared_left_data.data.nec.custom2,infrared_left_data.data.nec.key1,infrared_left_data.data.nec.key2); } } if(infrared_read(infrared_right,&infrared_right_data) == RT_EOK) { if(infrared_right_data.data.nec.repeat) { rt_kprintf("right repeat%d\n",infrared_right_data.data.nec.repeat); } else { rt_kprintf("right custom1:0x%02X custom2:0x%02X key1:0x%02X,key2:0x%02X\n",infrared_right_data.data.nec.custom1,infrared_right_data.data.nec.custom2,infrared_right_data.data.nec.key1,infrared_right_data.data.nec.key2); } } if(infrared_read(infrared_left_front,&infrared_left_front_data) == RT_EOK) { if(infrared_left_front_data.data.nec.repeat) { rt_kprintf("left front repeat%d\n", infrared_left_front_data.data.nec.repeat); } else { rt_kprintf("left front custom1:0x%02X custom2:0x%02X key1:0x%02X key2:0x%02X\n", infrared_left_front_data.data.nec.custom1,infrared_left_front_data.data.nec.custom2,infrared_left_front_data.data.nec.key1,infrared_left_front_data.data.nec.key2); } } if(infrared_read(infrared_right_front,&infrared_right_front_data) == RT_EOK) { if(infrared_right_front_data.data.nec.repeat) { rt_kprintf("right front repeat%d\n", infrared_right_front_data.data.nec.repeat); } else { rt_kprintf("right front custom1:0x%02X custom2:0x%02X key1:0x%02X key2:0x%02X\n", infrared_right_front_data.data.nec.custom1,infrared_right_front_data.data.nec.custom2,infrared_right_front_data.data.nec.key1,infrared_right_front_data.data.nec.key2); } } rt_thread_mdelay(20); } ``` 总结: 1.代码框架建立在官方原本的基础上,但是思想已经完全不同,建议先阅读官方代码。 2.如果要增加通道步骤如下: 1)在drv.infrared.h 中增加引脚编号宏定义,在receive init中增加初始化,并且增加引脚的中断服务函数(参考已有的通道) 2)infrared.h的infrared enum中增加对应编号 3)infrared.c中增加对应引脚的infrared class 实例对象 3.依赖于hwtimer.h驱动以及gpio驱动 4.代码测试已经通过,但是写法上还有改进空间,有兴趣的可以自行研究
5
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
jsrdczy
这家伙很懒,什么也没写!
文章
1
回答
0
被采纳
0
关注TA
发私信
相关文章
1
潘多拉 例程-05 红外包引入后报错(hwtimer.h找不到)
2
infrared红外遥控软件包如何使用
3
[讨论]关于自学习型红外遥控的软件实现--已实现基本功能,待完善.
4
RT_Thread的官方在不在关于红外框架infrared_frame
5
潘多拉-软件包-红外框架 定时器如何配置?
6
RealTouch加装内置红外接收头
7
[RealTouch例程]红外遥控器的使用
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部