# chhol_cc9d_light **Repository Path**: lee8871/chhol_cc9d_light ## Basic Information - **Project Name**: chhol_cc9d_light - **Description**: 用于MCU的Chhol通信库。用CC9D协议和Chhol模块通信 - **Primary Language**: C/C++ - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-09 - **Last Updated**: 2025-12-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 斥候模块的命令串口支持 此路径提供了对*斥候无线模块*命令串口的协议支持。 命令串口采用*CC9D协议*,此协议可以将串口数据进行分组,并规定了每个分组通信地址信息。 有关CC9D协议更多详细信息,请参阅 [DL-XLxxUserManual.pdf 第6章](../DL-XLxxUserManual.pdf)。 在此路径下包含多个源文件,参见下表: | 文件名 | 作用说明 | |---------------------|--------------------------------------------------------------| | byte_queue.c
byte_queue.h | 实现比特队列,比特队列不是必须的,但是在使用串口中断接收数据时,在中断线程使用队列缓存数据,然后在主线程进行处理,是十分有效的策略。 | | cc9d.c
cc9d.h | 实现CC9D。可以将任意串行的数据分组并形成CC9D包,或者将CC9D包转换为连续的数据,在流中传输。 | | crc8.c
crc8.h | 实现CRC-8校验算法。cc9d.c会用到这一文件。 | | typedef.h | 定义常用的类型别名的头文件。 | ## 程序移植 当您已经有一个C/C++工程,想要添加对CC9D的支持,您需要做以下操作: ### 1. 添加源文件 您需要将此路径下的文件添加到工程中,文件夹下的c文件应当随工程一起编译。(如果不使用队列,则不需要byte_queue.c) ### 2. 初始化 调用`void cc9d_init(sCc9dPkg pkg_mem_type* pkg)`进行初始化。 此函数的参数是一个CC9D包: ```c typedef struct { uint8 from_port; uint8 to_port; uint16 remote_addr; uint8 datas[64]; uint8 __crc; }sCc9dPkg; ``` CC9D程序内部不会申请大块的储存空间,您可以灵活的申请储存空间(例如使用`new`或全局变量),通过初始化交给CC9D,用于暂存接收到的包。 ### 3. 准备串口程序 不论是PC、树莓派还是微控制器,都需要准备好串口收发程序。 CC9D使用两个函数作为串口接口: #### 3-1. 串口收到数据函数 当串口收到数据时,需要调用cc9d_recvbyte,并将收到的数据按顺序传递给cc9d。 ```c void cc9d_recvbyte(byte b); ``` #### 3-2. 串口发出数据 cc9d需要发送1byte时,会调用此函数: ```c extern void _cc9d_sendByte(uint8 b); ``` 请注意,您需要调用`cc9d_recvbyte(byte b)`将收到的数据给CC9D。 相反的,您需要编写一个名为`_cc9d_sendByte(uint8 b)`的函数,CC9D会在需要发送数据时调用您编写的函数。 在CC9D中,凡是需要您实现,由CC9D调用的函数,都以下划线开头,并标记为`extern`。 ### 4. 准备接收到包的程序 在CC9D收到完整的包后,会调用这一函数: ```c sCc9dPkg* _cc9d_receivePkg(sCc9dPkg* pkg, uint8 data_len); ``` 建议您根据接收到包的端口号选择特定的函数处理这个包: ```c sCc9dPkg* _cc9d_receivePkg(sCc9dPkg* pkg, uint8 data_len) { switch (pkg->to_port) { case 16://16端口绑定到LED控制 ledControlReceivePkg(pkg, data_len); break; case 32://32端口绑定到ADC adcReportGetPkg(pkg, data_len); break; default://其他端口收到数据时,报告错误。 reportBadPort(pkg, data_len); break; } return pkg; } ``` 请注意,您调用`cc9d_recvbyte()`时,如果程序判断已经收到了一个包,就会在`cc9d_recvbyte()`中调用`_cc9d_receivePkg()`。对于嵌入式编程,如果您在串口中断内调用 `cc9d_recvbyte()`,那么`_cc9d_receivePkg()`也会在中断线程上执行。 此函数的返回值是一个CC9D包。如果您在`_cc9d_receivePkg()`返回后还需要使用pkg中的数据,您就需要分配新的内存空间,供CC9D接收下一个包使用,这种情况下,您需要将新分配的空间作为返回值。 相反的,如果在函数返回后不再需要使用包中的数据,就可以将参数pkg直接返回。 ### 5. 发送包 在发送包时,您需要准备一个sCc9dPkg包,填入想要发送的数据和目标地址,然后调用`void cc9d_SendPkg(sCc9dPkg pkg_mem_type* pkg, uint8 data_len)` ```c static void sendAdcPkg(int32 adc_value){ static uint16 sno = 0; sCc9dPkg send_pkg; send_pkg.from_port = 32; send_pkg.to_port = 32; send_pkg.remote_addr = 0x0000; send_pkg.datas[0] = (adc_value >> 0) & 0xff; send_pkg.datas[1] = (adc_value >> 8) & 0xff; send_pkg.datas[2] = (sno >> 0) & 0xff; send_pkg.datas[3] = (sno >> 8) & 0xff; cc9d_SendPkg(&send_pkg, 4); printf("GPIO A0 voltage: %f\n", Adc_getVoltage((uint16)adc_value)); sno++; } ``` 函数`cc9d_SendPkg()`会多次调用`_cc9d_sendByte()`,完成发送后返回。如果`_cc9d_sendByte()`采用等待串口发送完成后发送下一字节的策略,可能会消耗较多CPU资源。 在函数返回后,就可以释放send_pkg空间了。