完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
IIC总线上挂载多个从机的程序实现
IIC简介: 1、I2C总线具有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL 2、IIC总线上可以挂很多设备:多个主设备,多个从设备(外围 设备)。 3、多主机会产生总线裁决问题。当多个主机同时想占用总线时,企图启动总线传输数据,就叫做总线竞争。I2C通过总线仲裁,以决定哪台主机控制总线 在一般的项目中,一般不会涉及到IIC总线上挂载多主机多从机的情况。但挂载单个主机多个从机的情况还是有的。 在嵌入式领域:要不专注于硬件的设计,要不专注于软件的实现。当然最好两者都兼备。相对来说,软件层面的复杂度会相对高一点,在项目开发所占的任务比重也比较大,特别是一些组网的大型项目,往往还会涉及到上位机测试软件的开发等。本篇主要讲述STM32系列单片机的IIC挂载多个从机的程序实现。 1、项目的硬件参考电路: 如上图,将LIS2HH12加速度传感器、LPS25HB气压传感器通过IIC总线相连,与STM32Lxx 系列MCU的管脚PB6PB7 相连。 2、程序实现: 对于一个嵌入式软件工程师来说,IIC通信的基本知识需要了解,不过最重要的还是关心程序如何实现。 ST公司目前将STM32全系列都是支持HAL库的开发。cubeMx软件可以外设的驱动程序自动生成。但是多说情况下,还是需要手工改写。要不怎么称得上嵌入式软件开发工程师呢? 一般来说,对于嵌入式领域的单片机程序开发, 程序开头都会做一些初始化,初始化完成后然后进入一个死循环while(1),这对大多数没有操作系统的单片机软件来说。 我们也不例外,请看下面的程序框架: 2.1、程序框架设计: int main(void) { HAL_Init(); SystemClock_Config(); //系统时钟初始化 MX_I2C1_Init(); //外设IIC的初始化,PB6PB7,对应的外设IIC1 /* 看门狗初始化 */ MX_IWDG_Init(); HAL_IWDG_Refresh(&hiwdg); /*加速度传感器的配置*/ BSP_ACC_Init(&dev_ctx); BSP_ACC_Config(&dev_ctx); /*气压计的配置及功能实现*/ BSP_BARO_Init(&dev_baro)); BSP_BARO_Config(&dev_baro); while(1) { /*加速度传感器运用中断方式实现,所以while(1)中就出添加加速度的处理程序了*/ /*气压计的处理程序*/ BSP_BARO_handle(&dev_baro); } } 2.2 IIC 总线接口程序实现: 根据电路图和传感器的数据手册,进行如下的配置 uint8_t MX_I2C1_Init(void) //加速度、气压传感器SensorIIC接口 { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; // hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0x34; //这里的排至值并不影响。因为后面我们IIC的读写程序不用库函数,而是重写IIC的读写功能。 hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0;//这里的排至值并不影响。因为后面我们IIC的读写程序不用库函数,而是重写IIC的读写功能。 hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } if( HAL_I2C_GetState( &hi2c1) == HAL_I2C_STATE_READY ) { return 0; } else { return 1; } } 2.3 加速度传感器的配置: 这里我们定义了传感器对象的一个结构体,将此结构体的指针指向两个IIC的读写程序platform_write、platform_read。应为传感器挂载在IIC1上,这里将传感器结构体指针的句柄定位为IIC1的地址。 I2C_HandleTypeDef hi2c1; //传感器的I2C接口 # define SENSOR_BUS hi2c1 void BSP_ACC_Init(lis2hh12_ctx_t *dev_acc) { dev_acc->write_reg = platform_write; dev_acc->read_reg = platform_read; dev_acc->handle = &SENSOR_BUS; BSP_ACC_IO_ITConfig(); // 使能ACC MEMS 中断 } //使能加速度传感器的中断管脚功能。 void BSP_ACC_IO_ITConfig( void ) { /* At the moment this feature is only implemented for LPS22HB */ GPIO_InitTypeDef GPIO_InitStructureInt1; /* Enable INT1 GPIO clock */ __GPIOA_CLK_ENABLE(); /* Configure GPIO PINs to detect Interrupts */ GPIO_InitStructureInt1.Pin = GPIO_PIN_0; GPIO_InitStructureInt1.Mode = GPIO_MODE_IT_RISING; GPIO_InitStructureInt1.Speed = GPIO_SPEED_MEDIUM; GPIO_InitStructureInt1.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStructureInt1); /* Enable and set EXTI Interrupt priority */ HAL_NVIC_SetPriority(EXTI0_IRQn, 4, 0x00); } /************************************************************************ * 函数名称:BSP_ACC_Config(lis2hh12_ctx_t *dev_acc) * 功 能: 加速度配置 * 输入参数:无 * 返 回 值:dev_acc 结构体 * 其 他:无 ************************************************************************/ void BSP_ACC_Config(lis2hh12_ctx_t *dev_acc) { /* Check device ID */ lis2hh12_dev_id_get(dev_acc, &whoamI); if (whoamI != LIS2HH12_ID) { while(1) { /* manage here device not found */ } } /* Restore default configuration */ lis2hh12_dev_reset_set(dev_acc, PROPERTY_ENABLE); do { lis2hh12_dev_reset_get(dev_acc, &rst); } while (rst); /* Enable Block Data Update */ lis2hh12_block_data_update_set(dev_acc, PROPERTY_ENABLE); /* Set full scale */ lis2hh12_xl_full_scale_set(dev_acc, LIS2HH12_8g); //在加速度全域范围内运行【-8g:8g】 /* Configure filtering chain */ /* Accelerometer data output- filter path / bandwidth */ lis2hh12_xl_filter_aalias_bandwidth_set(dev_acc, LIS2HH12_AUTO); // 自适应 bandwidth lis2hh12_xl_filter_out_path_set(dev_acc, LIS2HH12_BYPASSED); // 开启内部低通滤波 lis2hh12_xl_filter_low_bandwidth_set(dev_acc, LIS2HH12_LP_ODR_DIV_9); //设置低通滤波的频率 /* Accelerometer interrrupt - filter path / bandwidth */ lis2hh12_xl_filter_int_path_set(dev_acc, LIS2HH12_HP_DISABLE); //开启 内部高通滤波 /* Set Output Data Rate */ lis2hh12_xl_data_rate_set(dev_acc, LIS2HH12_XL_ODR_50Hz); // ODR 设为100Hz #ifdef FIFO_ACC lis2hh12_fifo_mode_set(dev_acc,LIS2HH12_STREAM_MODE); // 设置 FIFO Mode lis2hh12_fifo_watermark_set(dev_acc,PROPERTY_ENABLE); //开启watermark lis2hh12_pin_int1_route_t pinValue; pinValue.int1_drdy = 0; pinValue.int1_fth = 1; pinValue.int1_inact = 0; pinValue.int1_ig1 = 0; pinValue.int1_ig2 = 0; pinValue.int1_ovr = 0; lis2hh12_pin_int1_route_set(dev_acc,pinValue); //设置中断 lis2hh12_fifo_watermark_set_level(dev_acc,THRESH_MASK); #endif }; 加速度传感器的中断管脚对应的中断服务函数: 在中断函数中实现计步功能。 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_0) // { ACC_DRY_Flag = SET; lis2hh12_handle(&dev_ctx); } } 2.4 气压传感器的配置,可以仿写加速度传感器的实现: void BSP_ACC_Init(lps25hb_ctx_t *dev_ctx) { dev_ctx.write_reg = platform_write; dev_ctx.read_reg = platform_read; dev_ctx.handle = &hi2c1; } void BSP_ACC_Config(lps25hb_ctx_t *dev_ctx) { /* Check device ID */ whoamI = 0; lps25hb_device_id_get(&dev_ctx, &whoamI); if ( whoamI != LPS25HB_ID ) while(1); /*manage here device not found */ /* Restore default configuration */ lps25hb_reset_set(&dev_ctx, PROPERTY_ENABLE); do { lps25hb_reset_get(&dev_ctx, &rst); } while (rst); /* Enable Block Data Update */ lps25hb_block_data_update_set(&dev_ctx, PROPERTY_ENABLE); /* Set Output Data Rate */ lps25hb_data_rate_set(&dev_ctx, LPS25HB_ODR_1Hz); } 2.5气压器的处理测试程序 void BSP_BARO_handle(lps25hb_ctx_t *dev_ctx); { while(1) { HAL_IWDG_Refresh(&hiwdg); /* Read output only if new value is available */ lps25hb_reg_t reg; lps25hb_status_get(&dev_ctx, ®.status_reg); if (reg.status_reg.p_da) { memset(data_raw_pressure.u8bit, 0x00, sizeof(int32_t)); lps25hb_pressure_raw_get(dev_ctx, data_raw_pressure.u8bit); pressure_hPa = lps25hb_from_l***_to_hpa( data_raw_pressure.i32bit); } if (reg.status_reg.t_da) { memset(data_raw_temperature.u8bit, 0x00, sizeof(int16_t)); lps25hb_temperature_raw_get(dev_ctx, data_raw_temperature.u8bit); temperature_degC = lps25hb_from_l***_to_degc( data_raw_temperature.i16bit); } HAL_Delay(500); } } 3、重写IIC的读写程序 以为加速度传感器的程序为例,当然气压器的IIC读写程序可以类似仿写。 读写时将从机的地址要写入 #define LIS2HH12_I2C_ADD_L 0x3DU /* * @brief Write generic device register (platform dependent) * * @param handle customizable argument. In this examples is used in * order to select the correct sensor bus handler. * @param reg register to write * @param bufp pointer to data to write in register reg * @param len number of consecutive register to write * */ static int32_t platform_write(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len) { if (handle == &hi2c1) { HAL_I2C_Mem_Write(handle, LIS2HH12_I2C_ADD_L, reg, I2C_MEMADD_SIZE_8BIT, bufp, len, 1000); } return 0; } /* * @brief Read generic device register (platform dependent) * * @param handle customizable argument. In this examples is used in * order to select the correct sensor bus handler. * @param reg register to read * @param bufp pointer to buffer that store the data read * @param len number of consecutive register to read * */ static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len) { if (handle == &hi2c1) { HAL_I2C_Mem_Read(handle, LIS2HH12_I2C_ADD_L, reg, I2C_MEMADD_SIZE_8BIT, bufp, len, 1000); } return 0; } ok,将代码烧录到板子上,测试成功。debug 可以看到气压计和计步值都正常输出了。 总结: ST的Mems扩展板的示例程序上有IIC总结挂载多个从机的Demo,但是移植程序比较困难。因为需要改写很多内容。 这个示例比较简单实用。当然ST官网还提供了很多示例,根据实际项目需要可以添加需要的传感器功能。 |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2956 浏览 16 评论
3458 浏览 1 评论
9002 浏览 16 评论
4051 浏览 18 评论
1112浏览 3评论
573浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
570浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2303浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1859浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 02:07 , Processed in 1.395776 second(s), Total 80, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号