# 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空间了。