IIC總線上掛載多個從機的程序實現

IIC總線上掛載多個從機的程序實現

IIC簡介:

在這裏插入圖片描述

1、I2C總線具有兩根雙向信號線,一根是數據線SDA,另一根是時鐘線SCL

2、IIC總線上可以掛很多設備:多個主設備,多個從設備(外圍 設備)。

3、多主機會產生總線裁決問題。當多個主機同時想佔用總線時,企圖啓動總線傳輸數據,就叫做總線競爭。I2C通過總線仲裁,以決定哪臺主機控制總線

在一般的項目中,一般不會涉及到IIC總線上掛載多主機多從機的情況。但掛載單個主機多個從機的情況還是有的。

在嵌入式領域:要不專注於硬件的設計,要不專注於軟件的實現。當然最好兩者都兼備。相對來說,軟件層面的複雜度會相對高一點,在項目開發所佔的任務比重也比較大,特別是一些組網的大型項目,往往還會涉及到上位機測試軟件的開發等。本篇主要講述STM32系列單片機的IIC掛載多個從機的程序實現。

1、項目的硬件參考電路:

在這裏插入圖片描述

如上圖,將LIS2HH12加速度傳感器、LPS25HB氣壓傳感器通過IIC總線相連,與STM32Lxx 系列MCU的管腳PB6\PB7 相連。

2、程序實現:

對於一個嵌入式軟件工程師來說,IIC通信的基本知識需要了解,不過最重要的還是關心程序如何實現。

ST公司目前將STM32全系列都是支持HAL庫的開發。cubeMx軟件可以外設的驅動程序自動生成。但是多說情況下,還是需要手工改寫。要不怎麼稱得上嵌入式軟件開發工程師呢?

一般來說,對於嵌入式領域的單片機程序開發,
程序開頭都會做一些初始化,初始化完成後然後進入一個死循環while(1),這對大多數沒有操作系統的單片機軟件來說。
我們也不例外,請看下面的程序框架:

2.1、程序框架設計:

int main(void)
{
   	HAL_Init();		
	SystemClock_Config();     //系統時鐘初始化
	MX_I2C1_Init();                 //外設IIC的初始化,PB6\PB7,對應的外設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, &reg.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_lsb_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_lsb_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官網還提供了很多示例,根據實際項目需要可以添加需要的傳感器功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章