娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

STM32 IIC雙機通信—— HAL庫硬件IIC版

發布者:Weasel最新更新時間:2025-02-19 來源: cnblogs關鍵字:STM32  IIC  雙機通信  HAL庫 手機看文章 掃描二維碼
隨時隨地手機看文章

  關于IIC的原理這里我就不多說了,網上有很多很好的解析,如果要看我個人對IIC的理解的話,可以點擊查看,這里主要講一下怎樣利用STM32CubeMx實現IIC的通訊,經過個人實踐,感覺HAL庫的硬件IIC要比標準庫的穩定。好了,下面就從STM32CubeMx 配置開始一步步實現IIC通訊。

  STM32CubeMx的配置,這里關于新建工程的步驟我就不細說了,如果還不會操作STM32CubeMx 的可以點擊查看, 這里主要對IIC的配置進行說明。

  

  了解IIC的都知道,IIC通信有主從機之分,用兩片STM32進行IIC通信當然也不例外,不過使用STM32CubeMx 配置有一個好處,就是不用分別配置主從機,在STM32CubeMx 配置里面,主從機的配置是一樣,唯一不同的就是IIC的地址如上圖,這個地址很重要,只要配置好了,基本就成功了。

  還有一個要注意的,就是IIC的SDA、SCK引腳要配置成NPP模式,不然容易出現信號線忙,檢測不到從機的情況。

  

  配置配好后我們生成代碼,就可以進行通信了,主從機核心代碼如下:

 

  下面是主機的重要代碼:


/* I2C2 init function  IIC配置*/

static void MX_I2C2_Init(void)

{


  hi2c2.Instance = I2C2;

  hi2c2.Init.Timing = 0x10805D88;

  hi2c2.Init.OwnAddress1 = 20;        //用戶自己配置的地址

  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

  hi2c2.Init.OwnAddress2 = 0;        

  hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;

  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;

  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

  if (HAL_I2C_Init(&hi2c2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }


    /**Configure Analogue filter 

    */

  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }


    /**Configure Digital filter 

    */

  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }


}


while(HAL_I2C_Master_Transmit_IT(&hi2c2 ,0x0b,&BUFF[0], 1)!= HAL_OK){}   

//IIC主機發送函數,主要IIC配置好了,這個可以添加到main函數里面測試


關于STM32CubeMx的HAL庫IIC收發有幾種函數,用戶可以根據自己不同的需求進行選擇,以下就是主要的幾個HAL庫IIC收發函數:


/* 第1個參數為I2C操作句柄

   第2個參數為從機設備地址

   第3個參數為從機寄存器地址

   第4個參數為從機寄存器地址長度

   第5個參數為發送的數據的起始地址

   第6個參數為傳輸數據的大小

   第7個參數為操作超時時間   */

HAL_I2C_Mem_Write(&hi2c2,salve_add,0,0,PA_BUFF,sizeof(PA_BUFF),0x10);


HAL_I2C_Mem_Write_IT();


HAL_I2C_Mem_Read();


HAL_I2C_Mem_Read_IT();


HAL_I2C_Mem_Read_DMA();


HAL_I2C_Mem_Write_DMA();


/*    不需要用到寄存器地址的主機HAL庫IIC收發函數   */

HAL_I2C_Master_Receive();     //STM32 主機接收,不需要用到寄存器地址

HAL_I2C_Master_Transmit();


HAL_I2C_Master_Receive_IT();   //中斷IIC接收 

HAL_I2C_Master_Receive_DMA();  //DMA 方式的IIC接收  


HAL_I2C_Master_Transmit_IT();   //中斷IIC發送  


HAL_I2C_Master_Transmit_DMA();   //DMA 方式的IIC發送  


HAL_I2C_Master_Transmit(&hi2c2,0x0B,PA_BUFF,sizeof(PA_BUFF),0x10); //STM32 主機發送 


/* 不需要用到寄存器地址的從機HAL庫IIC收發函數   */ 

HAL_I2C_Slave_Receive();    //STM32 從機機接收,不需要用到寄存器地址 

 

HAL_I2C_Slave_Transmit();   //STM32 從機機發送,不需要用到寄存器地址  


HAL_I2C_Slave_Receive_IT(); 


HAL_I2C_Slave_Receive_DMA(); 


HAL_I2C_Slave_Transmit_IT();


HAL_I2C_Slave_Transmit_DMA();


我這里因為只是做兩個STM32間的單向通行而已,不需要對寄存器進行寫數據。


所以主機發送函數選擇了 HAL_I2C_Master_Transmit( ); 函數,而我從機則選擇HAL_I2C_Slave_Receive( );函數,從機代碼如下:


/*   I2C2 init function 從機IIC初始化配置   */

static void MX_I2C2_Init(void)

{


  hi2c2.Instance = I2C2;

  hi2c2.Init.Timing = 0x10805D88;

  hi2c2.Init.OwnAddress1 = 0x0A;

  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

  hi2c2.Init.OwnAddress2 = 0;

  hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;

  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;

  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

  if (HAL_I2C_Init(&hi2c2) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }


    /**Configure Analogue filter 

    */

  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }


    /**Configure Digital filter 

    */

  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }


}


while(HAL_I2C_Slave_Receive(&hi2c2, RE_BUFF, 1, 100)!= HAL_OK) {} 

// 在配置好IIC后,可直接把該函數放到main函數測試,第一個參數是IIC通道選擇,第二個參數是接收緩存,第三個數據的是接收長度,第四個參數是超時時間


  經過測試,發現如果發送數據過多,用硬件I2C收發的話,使用中斷會比較穩定

  作為從機,要與主機完成通信,有一個特別要注意的事情,就是IIC配置的地址要與主機發送的地址一致,否則無法完成應答。我一開始就是直接發送自己在軟件配置的IIC地址,可是沒有通信成功,檢查才發現,軟件配置好IIC后,生成代碼時,地址會最后一位補0,自動補夠8位;而我從機發送出來的地址,也會把你發送的地址最后一位改為0再發送,這個我查了一下函數地層,好像是因為這是是發送函數,所以直接幫你把R/W位改為0了。所以導致我一開始怎么都調不通,使用邏輯分析儀后,分析采集到的數據才發現這個問題,于是我,直接手動改從機的IIC地址,改成邏輯分析儀發出來的地址一樣,這樣就通了。

 

  通信結果如圖所示:

  

 

補充2點要注意的:

  1. IIC硬件連接的時候SDA跟SCL總線注意都要上拉一個4.7K的電阻,否則IIC無法工作;

  2. 使用主從收發函數時,發送的地址要注意。如果是發送函數,發送出的地址最后一位 R/W 位如果不為0,則HAL庫函數會地址把最后一位修改為0,再把地址發送出去,但是如果地址最后一位 R/W 位為0,函數就不會對地址進行修改,直接把地址發送出去;如果是接收函數,發送出去的地址最后一位 R/W位 不為1,則HAL庫函數會把地址最后一位修改為1,再把地址發送出去,但是如果地址最后一位 R/W 位為1,函數就不會對地址進行修改,直接把地址發送出去.。所以從機地址設置,一定要與主機發出的地址一致才能正確應答。

  例如:

  (1) HAL_I2C_Master_Receive(&hi2c2,0x0a,(uint8_t *)test,sizeof(test),1000); 因為這個是讀出數據函數,這里發送的地址位第8位地址位 R/W 位應該為 1,發送地址 0x0a 硬件會把最后一位改為0,把地址變成0xb 再把 0x0b這個地址發送出去 ;如果地址最后一位R/W是 1,發送地址是 0x0b ,因為最后一位為 1,那么該函數發送的地址就不會對發送的地址最后一位R/W為做出修改,直接把 0x0b 發送出去,發出去的地址依然為0x0b。

 ?。?) HAL_I2C_Master_Transmit(&hi2c2,0x0f,(uint8_t *)test,sizeof(test),1000); 因為這個是寫入數據函數,R/W 位為 0,發送地址 0x0f 硬件會把最后一位改為 0 變成 0xe,如果發送的地址是 0xa ,則不會對地址進行修改,直接把地址 0x0a 發送出去。

  

  現在我以F40X系列的STM32 的 IIC 讀函數為例子來翻一下函數地層分析造成這個問題的原因:

  

  來到地層我們找到發送地址的函數;

  

  

  

  上面跳轉到這里我們就接近真相了,上圖1是跳轉下去的 IIC 寫函數的地層,2 是 IIC 跳轉下去的讀函數的地層,這里 ADDRESS 就是用戶寫進IIC發送讀取函數里的尋址地址了,接下來到重點了,對于I2C_OAR1_ADD0 我們再次跳轉分析下去看看;

  

  從這里接收函數我們可以看到,I2C_OAR1_ADD0 最終的值應該為 0x00000001,我們依舊以地址 0x 0b 為例: 0x 0b = 0000 1011 , 由或運算的定義我們可知,數據再做或運算 (|)時, 參加運算的兩個對象只要有一個為1,其值為1 , 所以 (00000001) | (0000 1011)= 0000 1011= 0x0b 。這時如果地址為 0x0xa(0000 1010),則會出現地址位最后一位R/W位被改為1的情況,運算過程為(00000001) | (0000 1010)= 0000 1011 = 0x0b ,結合這個地層運算,就不難解析為什么使用HAL庫的 IIC 接收函數,發送出去的地址會出現變化的情況了。

  至于發送函數同理,I2C_OAR1_ADD0 最終的值應該為 0x00000001,取反后就變成了 0x 1111 1110 ,由與運算(&)的定義可知兩位同時為“1”,結果才為“1”,否則為0。所以這里我們依舊以地址0x0b = 0000 1011 為例,(1111 1110) &(0000 1011)= 0000 1010 = 0x0b,所以發送函數把地址最后一位的R/W位改為了 0 ,而當地址為 0x0a = 0000 1010 時,我們再進行運算一下可得(1111 1110) &(0000 1010)= 0000 1010  = 0x0a , 地址沒有改變,所以這也就解析了上面我說的地址變化的問題了。


關鍵字:STM32  IIC  雙機通信  HAL庫 引用地址:STM32 IIC雙機通信—— HAL庫硬件IIC版

上一篇:STM32 HAL庫利用DMA實現串口不定長度接收方法
下一篇:STM32 GPIO重映射

推薦閱讀最新更新時間:2025-05-19 17:54

STM32硬件IIC
1 /** 2 * @brief 寫一個字節到I2C設備中 3 * @param 4 * @arg pBuffer:緩沖區指針 5 * @arg WriteAddr:寫地址 6 * @retval 正常返回1,異常返回0 7 */ 8 uint8_t I2C_ByteWrite(u8 pBuffer, u8 WriteAddr) 9 { 10 /* Send STRAT condition */ 11 I2C_GenerateSTART(macI2Cx, ENABLE); 12 13 I2CTimeout = I2CT_FLAG_TIMEOUT; 14 15 16 /*
[單片機]
stm32 IIC+MMA8451代碼
IIC驅動MMA8451通過串口發送顯示數據 5V 3.3V連一個就可以了。 SA0確定地址,接地。 SCl,SDA肯定要連。 以內接上拉電阻。 單片機源程序如下: /******************** (C) COPYRIGHT 2011 野火嵌入式開發工作室 ******************** * 文件名 :main.c * 描述 :I2C MMA8451測試 * 實驗平臺:野火STM32開發板 * 庫版本 :ST3.0.0 *********************************************************************************
[單片機]
STM32模擬IIC讀寫24CXX
文件(iic.h): #define SDA_IN() {GPIOB- CRL&=0X0FFFFFFF;GPIOB- CRL|=0X80000000;} #define SDA_OUT() {GPIOB- CRL&=0X0FFFFFFF;GPIOB- CRL|=0X30000000;} #define IIC_SCL PBout(6) #define IIC_SDA PBout(7) #define READ_SDA PBin(7) void bsp_iic_init(void); void bsp_iic_start(void); void bsp_iic_st
[單片機]
STM32 IIC讀取AT24C02
1、數量:I2C1與I2C2 2、時鐘: RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2,ENABLE); 3、IO配置為開漏輸出,在輸入時亦可讀取,此處使用功能復用。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE ); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_
[單片機]
雙機通信在CPCI總線上的實現
在電信、電力、國防等應用領域中,經常要求其所用設備有極高的實時性。當需要在各個設備間進行大容量的信息交換時,傳統的網絡包交換模式已不能很好地滿足實時性的要求。而借助于CPCI總線,兩個設備可以互訪對方的內存, 具有傳輸速度快、傳輸容量大和高可靠性等特點,非常適合大容量的信息傳遞。國家數字交換系統工程技術研究中心承擔的國家863計劃項目——“中國第三代移動通信系統”CDMA2000系統集成就選擇基于CPCI總線的多SBC平臺。各個SBC間的通信效率直接決定了整個系統性能的高低。 目前常用的實時操作系統如VxWorks、Lynx等,都針對CPCI總線實現了消息隊列,可用于SBC間的消息通信。但VxWorks、Lynx中消息傳遞的實
[嵌入式]
stm32F4XX之窗口看門狗 HAL庫
首先講一下獨立看門狗和窗口看門狗之間的區別。 獨立看門狗Iwdg——獨立于系統之外,因為有獨立時鐘,一般是外部低速時鐘。主要用于監視硬件錯誤。 窗口看門狗wwdg——系統內部的故障探測器,采用內部RCC時鐘,時鐘與系統相同。如果系統時鐘不走了,這個狗也就失去作用了。主要用于監視軟件錯誤 1)獨立看門狗沒有中斷,窗口看門狗有中斷 2)獨立看門狗有硬件軟件之分,窗口看門狗只能軟件控制 3)獨立看門狗只有下限,窗口看門狗又下限和上限 4)獨立看門狗是12位遞減的。窗口看門狗是7位遞減的 5)獨立看門狗是用的內部的大約40KHZ RC振蕩器(不受系統時鐘限制,即使系統時鐘壞了也能工作),窗口看門狗是用的系統時鐘
[單片機]
stm32F4XX之窗口看門狗 <font color='red'>HAL庫</font>
IIC總線時序的一點理解以及ACK和NACK(NAK)
關于IIC的響應問題:對于每一個接收設備(從設備,slaver),當它被尋址后,都要求在接收到每一個字節后產生一個響應。因此,the master device 必須產生一個額外的時鐘脈沖(第九個脈沖)用以和這個響應位相關聯。 在這個脈沖期間,發出響應的從設備必須將SDA拉低并在時鐘脈沖的高電平期間保持住。這表示該設備給出了一個ACK。如果它不拉低SDA線,就表示不響應(NACK)。 另外,在從機(發送方)發送完最后一個字節后主設備(接收方)必須產生一個不響應位,用以通知從機(發送方)不要再發送信息了,這樣從機就知道該將SDA釋放了,而后,主機發出一個停止位給slaver。 總結下,IIC通訊中,SDA 和 SCL 都
[單片機]
WinCE-IIC調試助手(S3C2410)
這兩天在調試一款新的硬件平臺,它采用的MCU依然是S3C2410。該平臺新增了一個RTC模塊,采用的芯片是DS1337。這是一個IIC接口的時鐘芯片。在開始調試時碰到了一些問題,MCU始終無法與DS1337通訊,走了些彎路,浪費了不少時間。后來發現是IIC的SDA和SCL接反了。為了以后能方便調試2410下的IIC設備,所以決定為2410的WinCE做一個IIC調試助手,以免下次再碰到類似的問題,而多花冤枉時間。 IIC調試助手的主要功能:檢測S3C2410 IIC-Bus上的設備,并給出對應的Slave Address。這樣,我們就可以快速判斷硬件是否有問題。除了偵測設備,同時也要支持讀和寫的功能。通過選擇,能方便控制IIC
[單片機]
WinCE-<font color='red'>IIC</font>調試助手(S3C2410)
小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 吴川市| 柳河县| 万安县| 永康市| 柘城县| 龙井市| 宜都市| 阜宁县| 北宁市| 越西县| 石家庄市| 策勒县| 拉孜县| 新泰市| 桂林市| 龙胜| 新巴尔虎右旗| 保康县| 师宗县| 昌江| 环江| 双江| 日喀则市| 阳曲县| 苗栗市| 潼关县| 眉山市| 梁山县| 峨边| 吴旗县| 清丰县| 泗水县| 区。| 保靖县| 宁波市| 瑞安市| 永德县| 资中县| 卓资县| 本溪市| 庄浪县|