# Chhol_STM32
**Repository Path**: lee8871/chhol_stm32
## Basic Information
- **Project Name**: Chhol_STM32
- **Description**: 使用STM32微控制器,与斥候无线模块通信的例程。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 4
- **Forks**: 0
- **Created**: 2024-08-01
- **Last Updated**: 2025-12-09
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 斥候无线模块-STM32开发例程包
这是使用STM32连接斥候模块进行无线组网通信的演示程序。
斥候(Chhol)模块的命令串口使用**CC9D协议**,外接的STM32微控制器需要实现此协议,
将带有地址信息的数据告知斥候模块,即可完成组网通信。
## 程序集说明
|路径|说明|
| -----------------| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|BSP|BSP,即板级支持包(Board Support Package),包含了和电路板与硬件相关的程序。具体来说,有Uart、LED、调试串口(用与printf输出程序)、和系统定时器。|
|Chhol|斥候无线模块相关的程序,这部分程序和硬件无关。
其中CC9D协议支持用于理解和构造与斥候模块通信的数据包;
Crc8用于完成CC9D中需要的循环冗余校验;
byte_queue是串口缓冲队列,用于暂存串口收发需要的数据。|
|Libraries|由`STMicroelectronics`提供的库函数。|
|chhol_base_demo|基础通信的例程,可以完成简单的数据收发。|
|chhol_adc_report|ADC采集上报例程,可以采集ADC值,定制上报,在ADC值大幅变化后也会上报。|
## chhol_base_demo介绍
这一演示程序使用常见的STM32开发板搭建,微控制器使用uart连接到斥候模块,和另一个斥候模块进行通信。
在这一演示中
### 硬件接线

其接线包括:
|GPIO编号|外部连接到|MCU内的功能|
| ----------| ----------------------------------------------------| -----------------------------------------------------|
|A5|红色LED|GPIO,控制红色LED的开关|
|A6|黄色LED|GPIO,控制黄色LED的开关|
|A7|绿色LED|GPIO,控制绿色LED的开关|
|C13|蓝色LED|GPIO,控制蓝色LED的开关|
|A2|斥候模块命令串口RX|USART2_TX,串口发送引脚|
|A3|斥候模块命令串口TX|USART2_RX,串口接收引脚|
|A9|USB转Uart的Rx|USART1_TX,串口发送引脚,用于printf|
|A10|USB转Uart(未连接)|USART1_RX,串口接收引脚,用于接收指令,现在未连接。|
### 软件介绍
整个系统的软件构成如下图:

### 接收无线包并处理
收到任何包后,CC9D会调用`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,因此,从此处收到的数据需要发给
ledControl(pkg, data_len);
break;
default://应该避免给模块发送目的端口号没有使用的包。
printf("Reserved port %d get a pkg, from %X.%d\n\tdatas: ", pkg->to_port, pkg->remote_addr, pkg->from_port);
for(int i=0;idatas[i]);
}
printf("\n");
break;
}
//返回pkg,意味着在退出此函数后CC9D继续使用pkg接收下一个包。
//如果程序中还要继续使用pkg中的数据,则必须准备一个未用的包指针,以供CC9D接收数据。
return pkg;
}
```
### 无线发出包
可以在任何程序序列中进行发送包,发送时需要进行以下操作:
1. 准备发送包结构体。
2. 填入地址和端口信息。
3. 填入数据。
4. 使用`void cc9d_SendPkg(sCc9dPkg pkg_mem_type* pkg, uint8 data_len)`进行发送,并以参数提供之前构建的结构体和需要发送的数据的长度。
发送的程序看起来是这样的:
```c
sCc9dPkg send_pkg;//发送包的数据体
send_pkg.from_port = 32;//源端口号
send_pkg.to_port = 32;//目的端口号
send_pkg.remote_addr = 0x0000;//目的地址
send_pkg.datas[0] = (sno >> 0) & 0xff;
send_pkg.datas[1] = (sno >> 8) & 0xff;
send_pkg.datas[2] = 0x56;
send_pkg.datas[3] = 0x78;
cc9d_SendPkg(&send_pkg,4);//调用这个函数,进行发送,第二个参数是数据部分的长度,单位是byte。
```
`cc9d_SendPkg`函数不会占用`send_pkg`空间,在`cc9d_SendPkg`返回后就可以释放`send_pkg`占用的空间。
另外需要注意,`cc9d_SendPkg`不是线程安全的,如果在中断线程和主线程内都会调用`cc9d_SendPkg`,就需要在调用前后添加临界区。
### 关于队列
在此程序中,广泛用到了循环队列。队列可以先接收多个字节并保存,过后在需要数据时,按顺序将数据取出。
在Uart接收数据时,在Uart的中断线程内,将数据存入队列,而后主线程中合适的位置,将数据取出并使用;
在Uart发送数据时,可以在主线程中连续的将大量字节写入队列,并开启发送中断;在中断线程中,每当一个字节发送回完成,就从队列中取出下一个字节发送,直到发送完成。
在 Uart2的接收和发送事物,以及printf的发送事务中,用到了队列。
需要注意,如果一次发送了过多数据,或者长时间没有从接收队列中取出数据,造成队列中储存超过其容量的数据,就会造成数据丢失。
可以在程序中设置队列的容量,其容量必须是2的整数幂。
```c
//串口收发缓冲区
static uint8 tx_buf[256];
static sByteQueue tx_queue;
static uint8 rx_buf[256];
static sByteQueue rx_queue;
//串口缓冲区初始化
static void initQueue(void) {
//初始化这两个队列
ByteQueue_init(&tx_queue, tx_buf, 256);
ByteQueue_init(&rx_queue, rx_buf, 256);
}
```
```c
static uint8 tx_buf[256];
static sByteQueue u1tx_queue;
static void initQueue(void) {
//初始化这两个队列
ByteQueue_init(&u1tx_queue, tx_buf, 256);
}
```
在程序中,队列的长度都被设置为256字节,实际可以存放255字节数据。
### 演示现象
将0002节点连接到STM32,0000连接到电脑,可以看到STM32每个2秒发送一个包。
发送命令到0002.16,可以控制LED点亮:
|命令|效果|
| -----------| -------------|
|0002.16:1|红色LED点亮|
|0002.16:2|黄色LED点亮|
|0002.16:3|绿色LED点亮|