基于STM32F103的CH101驱动程序移植

电子说

1.2w人已加入

描述

 

    有许多朋友在移植CHX01超声波传感器的过程中可能会遇到一些挑战,因此本文将重点介绍一些核心问题。虽然本来有想以手把手的方式来教授如何移植,但是由于之前移植的时候没有保存具体过程中的图文,所以需要花费很长的时间来重新完成这项工作。文末也提供了获取资源的接口,以帮助大家解决移植中出现的问题。

01准备资料

1.  从官网获取 SmartSonic_HelloChirp_Example_v1_31_0.exe 

源码(CHx01 官网源码的硬件平台 MCU: ATSAMG55;IDE:Microchip Studio)

2.  获取一个 STM32F103CB 的例程,比如我直接使用 STM32CubeF1 的模板。(当然你也可以用 STM32CubeIDE 创建一个工程)在这之前,假设你已经掌握了 Keil IDE 工程下的文件添加、编译等操作。比如,如下截图,我精简了STM32CubeF1 的模板,将工程名称修改为:SmartSonic_HelloChirp,并在工程下新建了 Drivers/BSP 和 Drivers/chirpmicro 两个Groups。

mcu

3.  将SmartSonic_HelloChirp_Example_v1_31_0文件中 

SmartSonic_HelloChirp_v1.31.0sourcedriverschirpmicro路径下的src 和  inc 文件夹拷贝到自己的STM32工程的smart-sonic_-hello-chirpDriverschirpmicro目录下

mcu

02API接口封装

我在之前的文章《超声波传感器(CHx01) 学习笔记 Ⅲ-API介绍》中提到所需API接口的相关内容。同样,在官方提供的例程中有一个 chbsp_dummy.c 文件,它使用  `attribute((weak))` 的方式提供了可选板支持包IO功能的虚拟实现,可以让平台依据需求来支持所需的功能。这种 `attribute((weak))` 例程能够满足来自其他代码的引用,避免链接出现错误,但它们不会执行任何操作。所有板卡支持包接口的详细信息,包括这些可选功能,都可以在 chirp_bsp.h  中找到。

 

/* Functions supporting debugging */
__attribute__((weak)) void chbsp_debug_toggle(uint8_t __attribute__((unused)) dbg_pin_num) {}
__attribute__((weak)) void chbsp_debug_on(uint8_t __attribute__((unused)) dbg_pin_num) {}
__attribute__((weak)) void chbsp_debug_off(uint8_t __attribute__((unused)) dbg_pin_num) {}
__attribute__((weak)) void chbsp_print_str(char *str) {
    (void)(str);
}
__attribute__((weak)) uint32_t chbsp_timestamp_ms() {
return 0;
}
__attribute__((weak)) int chbsp_i2c_deinit(void){
return 0;
}




/* Functions supporting interrupt-based operation */
__attribute__((weak)) void chbsp_group_io_interrupt_enable(ch_group_t *grp_ptr) {
    (void)(grp_ptr);
}
__attribute__((weak)) void chbsp_io_interrupt_enable(ch_dev_t *dev_ptr) {
    (void)(dev_ptr);
}
__attribute__((weak)) void chbsp_group_io_interrupt_disable(ch_group_t *grp_ptr) {
    (void)(grp_ptr);
}
__attribute__((weak)) void chbsp_io_interrupt_disable(ch_dev_t *dev_ptr) {
    (void)(dev_ptr);
}


/* Functions supporting non-blocking operation */
__attribute__((weak)) int chbsp_i2c_write_nb(ch_dev_t *dev_ptr, uint8_t *data, uint16_t num_bytes) {
    (void)(dev_ptr);
    (void)(data);
    (void)(num_bytes);
return 1;
}


__attribute__((weak)) 
int chbsp_i2c_mem_write_nb(ch_dev_t *dev_ptr, uint16_t mem_addr, uint8_t *data, uint16_t num_bytes) {
    (void)(dev_ptr);
    (void)(mem_addr);
    (void)(data);
    (void)(num_bytes);
return 1;
}


__attribute__((weak)) int chbsp_i2c_read_nb(ch_dev_t *dev_ptr, uint8_t *data, uint16_t num_bytes) {
    (void)(dev_ptr);
    (void)(data);
    (void)(num_bytes);
return 1;
}


__attribute__((weak)) int chbsp_i2c_mem_read_nb(ch_dev_t *dev_ptr, uint16_t mem_addr, uint8_t *data, uint16_t num_bytes) {
    (void)(dev_ptr);
    (void)(mem_addr);
    (void)(data);
    (void)(num_bytes);
return 1;
}




/* Functions supporting controlling int pins of individual sensors (originally only controllable in a group) */
__attribute__((weak)) void chbsp_set_io_dir_out(ch_dev_t *dev_ptr) {
    (void)(dev_ptr);
}
__attribute__((weak)) void chbsp_set_io_dir_in(ch_dev_t *dev_ptr) {
    (void)(dev_ptr);
}
__attribute__((weak)) void chbsp_io_clear(ch_dev_t *dev_ptr) {
    (void)(dev_ptr);
}
__attribute__((weak)) void chbsp_io_set(ch_dev_t *dev_ptr) {
    (void)(dev_ptr);
}
__attribute__((weak)) void chbsp_external_i2c_irq_handler(chdrv_i2c_transaction_t *trans){
    (void)(trans);
}

 

超声波传感器(CHx01) 学习笔记 Ⅱ- I2C读写操作》中有详细的介绍,按照上述API接口逐个封装函数内容即可。

03API接口验证

假设你已经将MAX3378EEUD和74LVC1T45用于IO口电平转换,接下来就是如何获取传感器的固定ID,以此来验证I2C通信接口的正确性。获取ID的方式可以帮助我们更好地验证I2C通信接口的封装正确性。

mcu

 获取传感器 ID 流程图

mcu

 获取传感器 ID I2C读时序图

04关键API接口介绍

`int chbsp_i2c_mem_read(ch_dev_t *dev_ptr, uint16_t mem_addr, uint8_t *data, uint16_t num_bytes)`

这个 API 使用内存寻址从I2C从机读取字节。需要封装成一个,指定一个字节寄存器地址并从Slave读取多个字节的函数。

与 STM32 HAL库相关的函数是:HAL_I2C_Mem_Read(&hi2c1, Address << 1, RegisterAddr, 1, (uint8_t *)(uint32_t)RegisterValue, (uint16_t)RegisterLen, 1000)

`int chbsp_i2c_read(ch_dev_t *dev_ptr, uint8_t *data, uint16_t num_bytes)`

这个 API 是原始的I2C从机读取字节。需要封装成一个,从Slave读取多字节的函数。

与 STM32 HAL库相关的函数是:HAL_I2C_Master_Receive(&hi2c1, (Address << 1), (uint8_t *)(uint32_t)data, (uint16_t)len, 1000)

`int chbsp_i2c_mem_write(ch_dev_t *dev_ptr, uint16_t mem_addr, uint8_t *data, uint16_t num_bytes)`

这个 API 使用内存寻址将字节写入I2C从机。需要封装成一个,指定一个字节寄存器地址并将多个字节写入从机的函数。

与 STM32 HAL库相关的函数是:HAL_I2C_Mem_Write(&hi2c1, Address << 1, RegisterAddr, 1, (uint8_t *)(uint32_t)RegisterValue, (uint32_t)RegisterLen, 1000)

`int chbsp_i2c_write(ch_dev_t *dev_ptr, uint8_t *data, uint16_t num_bytes)`

这个 API 是原始的将字节写入I2C从机。需要封装成一个,将多字节写入从机的函数。

与 STM32 HAL库相关的函数是:HAL_I2C_Master_Transmit(&hi2c1, (Address << 1), (uint8_t *)(uint32_t)data, (uint32_t)len, 1000)

`void chbsp_delay_ms(uint32_t num_ms)`

`void chbsp_delay_us(uint32_t us)`

这两个延时函数要精准,尤其是 chbsp_delay_ms 毫秒延时,会直接影响传感器的输出频率。

下面这两个函数,我们无需自行封装任何内容,但是它们非常重要。

`int chdrv_group_detect_and_program(ch_group_t *grp_ptr)`

这个函数用来检测、编程和启动传感器。对于每个检测到的传感器,会将传感器固件被编程到设备中,并设置应用程序I2C地址。然后传感器复位并开始执行。

一旦启动,传感器设备将开始内部初始化和自检序列。chdrv_group_wait_for_lock()函数可用于等待此序列在设备上完成。此函数完成后,将使设备的PROG引脚解除。

`void chdrv_group_measure_rtc(ch_group_t *grp_ptr)`

这个函数用来 校准传感器实时时钟。在这个函数里 触发IO引脚上的脉冲 时与选择的主处理器的时钟相关。

此函数在INT 引脚上向传感器设备发送一个脉冲(由主机MCU定时),然后回读每个单独设备上该脉冲期间经过的传感器RTC周期的计数。结果存储在每个设备的ch_dev_config结构中,随后在范围计算期间使用。

脉冲的长度为dev_ptr->rtc_cal_pulse_ms毫秒(通常为100)。此值在ch_init()期间设置。

如果有多个传感器时,校准脉冲会同时发送到所有设备。因此,所有连接的设备将看到相同的参考脉冲长度。

还需要实现两个外设功能

定时器,定时周期100ms,在定时器回调函数中周期性调用

`int chdrv_group_hw_trigger(ch_group_t *grp_ptr)` 启动硬件触发模式下开始测量。

int chdrv_group_hw_trigger(ch_group_t *grp_ptr) 函数通过简单地检测INT 引脚上每个传感器开始被触发的测量。在调用此函数之前,每个传感器必须已置于硬件触发模式。

GPIO外部中断,在外部中断回调函数中调用

`sensor_int_callback()` 检测传感器的中断信号。每次调用此函数时,都会在data_ready_devices变量中设置一个位以标识中断设备。当传感器产生中断(通过与active_devices变量比较找到)时,DATA_READY_FLAG被设置。该标志将在main()循环中检测到。

mcu

         一个完成的硬件触发INT硬件,并接收传感器返回的INT信号的时序图

05程序流程图

  主程序

mcu

  定时器服务程序  

mcu

INT 外部中断服务程序

mcu

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分