首頁 > 評測 > 【HC32L96PCTA測評】+UART+IIC測評

【HC32L96PCTA測評】+UART+IIC測評

  
  • 作者:
  • 來源:
  • [導讀]
  • 本帖最后由 hulai123456 于 2023-8-30 20:06 編輯 #申請原創(chuàng)# #技術資源# 【HC32L96PCTA測評】+UART+IIC+ADXL345實現(xiàn)簡單的姿態(tài)檢測 UART簡介 通用UART模塊支持以下基本功能 ■ 全雙工傳輸、半雙工傳輸、單

本帖最后由 hulai123456 于 2023-8-30 20:06 編輯

#申請原創(chuàng)# #技術資源#

【HC32L96PCTA測評】+UART+IIC+ADXL345實現(xiàn)簡單的姿態(tài)檢測


UART簡介
通用UART模塊支持以下基本功能
■ 全雙工傳輸、半雙工傳輸、單線半雙工傳輸
■ 可編程串行通信功能
     兩種字符長度:8比特、 9比特
     三種校驗方式:無檢驗、奇校驗、偶校驗
     三種停止長度:1比特、 2比特、 1.5比特
■ 16比特波特率發(fā)生器
■ 多機通訊
■ 硬件地址識別
■ 硬件流控
■ DMAC硬件傳輸握手

下圖為其結構框圖


我們需要對其進行初始化和一點點配置,實現(xiàn)printf打印功能,我們在這里將其配置成:
波特率:9600
停止位:1
校驗位:None
數(shù)據(jù)位:8

 

  1. void Uart0_Init(void)
  2. {
  3.         Uart0_GPIO_Init();
  4.         Uart0_Config(Value9600);
  5. }
復制代碼
  1. // UART0 GPIO 初始化
  2. void Uart0_GPIO_Init(void)
  3. {
  4.         stc_gpio_cfg_t stcGpioCfg;
  5.         DDL_ZERO_STRUCT(stcGpioCfg);
  6.         Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);//開啟GPIO外設時鐘
  7.         //TX
  8.         stcGpioCfg.enDir = GpioDirOut;
  9.         Gpio_Init(UART0_TX_PORT, UART0_TX_PIN, &stcGpioCfg);
  10.         Gpio_SetAfMode(UART0_TX_PORT, UART0_TX_PIN, GpioAf2);
  11.         
  12.         //RX
  13.         stcGpioCfg.enDir = GpioDirIn;
  14.         Gpio_Init(UART0_RX_PORT, UART0_RX_PIN, &stcGpioCfg);
  15.         Gpio_SetAfMode(UART0_RX_PORT, UART0_RX_PIN, GpioAf2);        
  16.         
  17. }
復制代碼
  1. //Uart0 配置
  2. void Uart0_Config(uint32_t BaudRate)
  3. {
  4.         stc_uart_cfg_t stcUartCfg;
  5.         DDL_ZERO_STRUCT(stcUartCfg);
  6.  
  7.         // 先禁止接收中斷
  8.         EnableNvic(UART0_2_IRQn, IrqLevel3, FALSE);        
  9.         Uart_DisableIrq(M0P_UART0, UartRxIrq);
  10.         
  11.         Sysctrl_SetPeripheralGate(SysctrlPeripheralUart0,TRUE);//開啟Uart0外設時鐘
  12.         stcUartCfg.enRunMode = UartMskMode1;//模式1
  13.         stcUartCfg.enStopBit = UartMsk1bit;//1位停止位
  14.         
  15.         switch(BaudRate)
  16.         {
  17.                 case Value1200:     stcUartCfg.stcBaud.u32Baud = 1200; break;
  18.                 case Value2400:     stcUartCfg.stcBaud.u32Baud = 2400; break;
  19.                 case Value4800:     stcUartCfg.stcBaud.u32Baud = 4800; break;
  20.                 case Value9600:     stcUartCfg.stcBaud.u32Baud = 9600; break;
  21.                 case Value19200:     stcUartCfg.stcBaud.u32Baud = 19200; break;
  22.                 case Value38400:     stcUartCfg.stcBaud.u32Baud = 38400; break;
  23.                 case Value57600:     stcUartCfg.stcBaud.u32Baud = 57600; break;
  24.                 case Value115200:     stcUartCfg.stcBaud.u32Baud = 115200; break;
  25.         }
  26.         
  27.         stcUartCfg.stcBaud.enClkDiv = UartMsk8Or16Div;//8分頻
  28.         stcUartCfg.stcBaud.u32Pclk = Sysctrl_GetPClkFreq();
  29.         Uart_Init(M0P_UART0, &stcUartCfg);
  30.         
  31.         
  32.         // 再開啟中斷
  33.         Uart_ClrStatus(M0P_UART0, UartRC);
  34.         Uart_EnableIrq(M0P_UART0,UartRxIrq);//接收中斷
  35.         EnableNvic(UART0_2_IRQn, IrqLevel3, TRUE);                 
  36. }
復制代碼
  1. int fputc(int ch, FILE *f) //重定向printf函數(shù)到uart0串口打印
  2. {
  3.         (void)f;//防止編譯報警告
  4.         Uart_SendDataPoll(M0P_UART0, (uint8_t)ch);
  5.         return ch;
  6. }
復制代碼

IIC簡介
HC32L96PCTA的I2C控制器支持以下特性:
■ 支持主機發(fā)送/接收,從機發(fā)送/接收四種工作模式
■ 支持標準(100Kbps) / 快速(400Kbps) / 高速(1Mbps) 三種工作速率
■ 支持7位尋址功能
■ 支持噪聲過濾功能
■ 支持廣播地址
■ 支持中斷狀態(tài)查詢功能

由于我們這里只有一個從機設備(其地址為0x53),因此用到的IIC功能其實用軟件模擬也能實現(xiàn),當然這里由于是測評,用的是硬件驅動。
其初始化代碼如下:

  1. #define MyIIC_SCL_PORT      (GpioPortB)
  2. #define MyIIC_SCL_PIN         (GpioPin8)
  3.  
  4. #define MyIIC_SDA_PORT     (GpioPortB)
  5. #define MyIIC_SDA_PIN        (GpioPin9)
復制代碼
  1. // IO端口配置
  2. static void MyIIC_PortCfg(void)
  3. {
  4.     stc_gpio_cfg_t stcGpioCfg;
  5.    
  6.     DDL_ZERO_STRUCT(stcGpioCfg);
  7.    
  8.     Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);   //開啟GPIO時鐘門控
  9.    
  10.     stcGpioCfg.enDir = GpioDirOut;                           ///< 端口方向配置->輸出   
  11.     stcGpioCfg.enOD = GpioOdEnable;                          ///< 開漏輸出
  12.     stcGpioCfg.enPu = GpioPuEnable;                          ///< 端口上拉配置->使能
  13.     stcGpioCfg.enPd = GpioPdDisable;                         ///< 端口下拉配置->禁止
  14.     stcGpioCfg.bOutputVal = TRUE;
  15.    
  16.     Gpio_Init(MyIIC_SCL_PORT,MyIIC_SCL_PIN,&stcGpioCfg);               ///< 端口初始化
  17.     Gpio_Init(MyIIC_SDA_PORT,MyIIC_SDA_PIN,&stcGpioCfg);
  18.    
  19.     Gpio_SetAfMode(MyIIC_SCL_PORT,MyIIC_SCL_PIN,GpioAf1);              ///< 配置PB08為SCL
  20.     Gpio_SetAfMode(MyIIC_SDA_PORT,MyIIC_SDA_PIN,GpioAf1);              ///< 配置PB09為SDA
  21. }
  22.  
  23. // I2C 模塊配置
  24. void MyI2c_Config(void)
  25. {
  26.         stc_i2c_cfg_t stcI2cCfg;
  27.         DDL_ZERO_STRUCT(stcI2cCfg);                            ///< 初始化結構體變量的值為0
  28.         
  29.         Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c0,TRUE); ///< 開啟I2C0時鐘門控
  30.         
  31.         stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq();             ///< 獲取PCLK時鐘
  32.         stcI2cCfg.u32Baud = 100000;                            ///< 100kHz
  33.         stcI2cCfg.enMode = I2cMasterMode;                      ///< 主機模式
  34.         stcI2cCfg.u8SlaveAddr = IIC_ADDR;                             ///< 從地址,主模式無效
  35.         stcI2cCfg.bGc = FALSE;                                 ///< 廣播地址應答使能關閉
  36.         I2C_Init(M0P_I2C0,&stcI2cCfg);                         ///< 模塊初始化
  37.         
  38.         MyIIC_PortCfg();// GPIO口配置
  39.         
  40.         delay1ms(2);
  41.         I2C_SetFunc(M0P_I2C0,I2cStart_En);                                                  //開始信號
  42. }
復制代碼

在初始化完成后,就根據(jù)例程中提供的數(shù)據(jù)讀取和寫入函數(shù),進行簡單的修改:

  1. /**
  2. ******************************************************************************
  3. ** \brief  主機接收函數(shù)
  4. **
  5. ** \param REGAddr從機寄存器地址,pu8Data讀數(shù)據(jù)存放緩存,u32Len讀數(shù)據(jù)長度
  6. **
  7. ** \retval 讀數(shù)據(jù)是否成功
  8. **
  9. ******************************************************************************/
  10. en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data,uint32_t u32Len,uint8_t REGAddr)
  11. {
  12.     en_result_t enRet = Error;
  13.     uint8_t u8i=0,u8State;
  14.    
  15.     I2C_SetFunc(I2CX,I2cStart_En);
  16.    
  17.     while(1)
  18.     {
  19.         while(0 == I2C_GetIrq(I2CX))
  20.         {;}
  21.         u8State = I2C_GetState(I2CX);
  22.         switch(u8State)
  23.         {
  24.             case 0x08:                                    //已發(fā)送起始條件,將發(fā)送SLA+R
  25.                 I2C_ClearFunc(I2CX,I2cStart_En);
  26.                 I2C_WriteByte(I2CX,IIC_WRITE_ADDR);                                //發(fā)送SLA+W
  27.                 break;
  28.             case 0x18:                                    //已發(fā)送SLA+W,并接收到ACK
  29.                 I2C_WriteByte(I2CX,REGAddr);              //發(fā)送寄存器地址
  30.                 break;
  31.             case 0x28:                                    //已發(fā)送數(shù)據(jù),接收到ACK
  32.                 I2C_SetFunc(I2CX,I2cStart_En);
  33.                 break;
  34.             case 0x10:                                    //已發(fā)送重復起始條件
  35.                 I2C_ClearFunc(I2CX,I2cStart_En);
  36.                 I2C_WriteByte(I2CX,IIC_READ_ADDR);                                //讀命令發(fā)送
  37.                 break;
  38.             case 0x40:                                    //已發(fā)送SLA+R,并接收到ACK
  39.                 if(u32Len>1)
  40.                 {
  41.                     I2C_SetFunc(I2CX,I2cAck_En);
  42.                 }
  43.                 break;
  44.             case 0x50:                                    //已接收數(shù)據(jù)字節(jié),并已返回ACK信號
  45.                 pu8Data[u8i++] = I2C_ReadByte(I2CX);
  46.                 if(u8i==u32Len-1)
  47.                 {
  48.                     I2C_ClearFunc(I2CX,I2cAck_En);        //讀數(shù)據(jù)時,倒數(shù)第二個字節(jié)ACK關閉
  49.                 }
  50.                 break;
  51.             case 0x58:                                    //已接收到最后一個數(shù)據(jù),NACK已返回
  52.                 pu8Data[u8i++] = I2C_ReadByte(I2CX);
  53.                 I2C_SetFunc(I2CX,I2cStop_En);             //發(fā)送停止條件
  54.                 break;   
  55.             case 0x38:                                    //在發(fā)送地址或數(shù)據(jù)時,仲裁丟失
  56.                 I2C_SetFunc(I2CX,I2cStart_En);            //當總線空閑時發(fā)起起始條件
  57.                 break;
  58.             case 0x48:                                    //發(fā)送SLA+R后,收到一個NACK
  59.                 I2C_SetFunc(I2CX,I2cStop_En);
  60.                 I2C_SetFunc(I2CX,I2cStart_En);
  61.                 break;
  62.             default:                                      //其他錯誤狀態(tài),重新發(fā)送起始條件
  63.                 I2C_SetFunc(I2CX,I2cStart_En);            //其他錯誤狀態(tài),重新發(fā)送起始條件
  64.                 break;
  65.         }
  66.         I2C_ClearIrq(I2CX);                               //清除中斷狀態(tài)標志位
  67.         if(u8i==u32Len)                                   //數(shù)據(jù)全部讀取完成,跳出while循環(huán)
  68.         {
  69.             break;
  70.         }
  71.     }
  72.     enRet = Ok;
  73.     return enRet;
  74. }
復制代碼
  1. /**
  2. ******************************************************************************
  3. ** \brief  主機發(fā)送函數(shù)
  4. **
  5. ** \param REGAddr從機寄存器地址,pu8Data寫數(shù)據(jù),u32Len寫數(shù)據(jù)長度,REGAddr操作寄存器地址
  6. **
  7. ** \retval 寫數(shù)據(jù)是否成功
  8. **
  9. ******************************************************************************/
  10. en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data,uint32_t u32Len,uint8_t REGAddr)
  11. {
  12.     en_result_t enRet = Error;
  13.     uint8_t u8i=0,u8State,u8Flag=FALSE;
  14.     I2C_SetFunc(I2CX,I2cStart_En);
  15.     while(1)
  16.     {
  17.         while(0 == I2C_GetIrq(I2CX))
  18.         {;}
  19.         u8State = I2C_GetState(I2CX);
  20.         switch(u8State)
  21.         {
  22.             case 0x08:                                 ///已發(fā)送起始條件
  23.                 I2C_ClearFunc(I2CX,I2cStart_En);
  24.                 I2C_WriteByte(I2CX,IIC_WRITE_ADDR);          ///從設備地址發(fā)送
  25.                 break;
  26.             case 0x18:                                 ///已發(fā)送SLA+W,并接收到ACK
  27.                                                                 I2C_WriteByte(I2CX,REGAddr);
  28.                                                                 break;
  29.             case 0x28:                                 ///上一次發(fā)送數(shù)據(jù)后接收到ACK
  30.                 if (u8i < u32Len)
  31.                 {
  32.                     I2C_WriteByte(I2CX,pu8Data[u8i++]);  ///< 繼續(xù)發(fā)送數(shù)據(jù)
  33.                 }
  34.                                                                 else
  35.                 {
  36.                     I2C_SetFunc(I2CX,I2cStop_En);     ///< 出停止條件
  37.                     u8Flag = TRUE;
  38.                 }
  39.                                                                 break;
  40.             case 0x20:                                 ///上一次發(fā)送SLA+W后,收到NACK
  41.                                                                 break;
  42.             case 0x38:                                 ///上一次在SLA+讀或寫時丟失仲裁
  43.                 I2C_SetFunc(I2CX,I2cStart_En);         ///當I2C總線空閑時發(fā)送起始條件
  44.                 break;
  45.             case 0x30:                                 ///已發(fā)送I2Cx_DATA中的數(shù)據(jù),收到NACK,將傳輸一個STOP條件
  46.                 I2C_SetFunc(I2CX,I2cStop_En);          ///發(fā)送停止條件
  47.                 break;
  48.             default:
  49.                 break;
  50.         }            
  51.         I2C_ClearIrq(I2CX);                            ///清除中斷狀態(tài)標志位
  52.         if(u8Flag == TRUE)  ///< 數(shù)據(jù)發(fā)送完成
  53.         {   
  54.             break;
  55.         }
  56.     }
  57.     enRet = Ok;
  58.     return enRet;
  59. }
復制代碼

自此,我們初步完成了I2C的初始化。

ADXL345簡介
一款加速度計,就不多介紹了,主要檢測其芯體在空間中X、Y、Z軸的數(shù)據(jù)在此,對其進行初始化和數(shù)據(jù)的采集

  1. //ADXL345設置偏移量
  2. void ADXL345_SetOffset(char xOffset, char yOffset, char zOffset)
  3. {
  4.         union
  5.         {
  6.                 unsigned char u8t;// 無符號
  7.                 char                                        q8t;// 有符號
  8.         }X_Offset;
  9.         
  10.                 union
  11.         {
  12.                 unsigned char u8t;// 無符號
  13.                 char                                        q8t;// 有符號
  14.         }Y_Offset;
  15.         
  16.                 union
  17.         {
  18.                 unsigned char u8t;// 無符號
  19.                 char                                        q8t;// 有符號
  20.         }Z_Offset;
  21.         
  22.         X_Offset.q8t = xOffset;
  23.         Y_Offset.q8t = yOffset;
  24.         Z_Offset.q8t = zOffset;
  25.         
  26.         I2C_MasterWriteData(M0P_I2C0, &X_Offset.u8t, 1, ADXL345_OFSX);
  27.         I2C_MasterWriteData(M0P_I2C0, &Y_Offset.u8t, 1, ADXL345_OFSY);
  28.         I2C_MasterWriteData(M0P_I2C0, &Z_Offset.u8t, 1, ADXL345_OFSZ);
  29.         
  30. }
復制代碼

數(shù)據(jù)初始化

  1. //ADXL345初始化配置
  2. void ADXL345_Init(void)
  3. {
  4.         MyI2c_Config();
  5.         delay1ms(10);
  6.         if(ADXL345_InitFlag==0)
  7.         {
  8.                 ADXL345_Ready();//ADXL345初始化配置
  9.         }
  10.  
  11. }
  12.  
  13. //ADXL345準備初始化
  14. void ADXL345_Ready(void)
  15. {
  16.         I2C_MasterReadData(M0P_I2C0, ADXL345_Buffer, 1, ADXL345_DEVID);
  17.         
  18.         delay1ms(2);
  19.         if(ADXL345_Buffer[0]==0xE5)//ADXL345的器件ID為0xE5
  20.         {        
  21.                 ADXL345_Buffer[0] = 0x08;
  22.                 I2C_MasterWriteData(M0P_I2C0, ADXL345_Buffer, 1, ADXL345_POWER_CTL);
  23.                
  24.                 delay1ms(3);
  25.                
  26.                 ADXL345_SetOffset((char)4,(char)0,(char)-7);//設置三個軸偏移量
  27.                
  28.                 ADXL345_InitFlag = 1;
  29.         }
  30.         else//加速度傳感器壞
  31.         {
  32.                 ADXL345_InitFlag = 0;
  33.         }
  34. }
復制代碼

數(shù)據(jù)采集處理打印輸出,需要對其進行數(shù)據(jù)轉換和濾波

  1. //ADXL345的X,Y,Z軸數(shù)據(jù)讀取
  2. void ADXL345_GetXYZValue(float *x, float *y, float *z)
  3. {
  4.         float X_Temp=0,Y_Temp=0,Z_Temp=0;
  5.         
  6.         I2C_MasterReadData(M0P_I2C0, ADXL345_Buffer, 6, ADXL345_DATAX0);
  7.         
  8.         X_Temp += (float)((short)(ADXL345_Buffer[1] << 8) + ADXL345_Buffer[0])/256;//數(shù)據(jù)組合再除以256(即轉換為g為單位)
  9.         Y_Temp += (float)((short)(ADXL345_Buffer[3] << 8) + ADXL345_Buffer[2])/256;
  10.         Z_Temp += (float)((short)(ADXL345_Buffer[5] << 8) + ADXL345_Buffer[4])/256;               
  11.         
  12.         
  13.         
  14.         *x = X_Temp;
  15.         *y = Y_Temp;
  16.         *z = Z_Temp;
  17. }
復制代碼
  1. //ADXL345數(shù)據(jù)收集,處理,輸出
  2. void ADXL345_Data_collection(void)
  3. {
  4.         float X_out = 0.0;
  5.         float Y_out = 0.0;
  6.         float Z_out = 0.0;
  7.         
  8.         float roll = 0.0;
  9.         float pitch = 0.0;
  10.         
  11.         if(ADXL345_InitFlag==1)//ADXL345初始化成功了
  12.         {
  13.                 delay1ms(10);
  14.                 ADXL345_GetXYZValue(&X_out, &Y_out, &Z_out);
  15.                
  16.                 roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
  17.                 pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;
  18.                
  19.                 // Low-pass filter
  20.                 rollF = 0.94 * rollF + 0.06 * roll;
  21.                 pitchF = 0.94 * pitchF + 0.06 * pitch;
  22.  
  23.                 printf("%.2f/%.2f\r\n",rollF, pitchF);
  24.                
  25.         }
  26.         else
  27.         {
  28.                 printf("ADXL345 Failure !!!");
  29.         }
  30. }
復制代碼

而后,在main函數(shù)中對其進行調用時鐘配置(和上期一樣)

  1. // 系統(tǒng)時鐘配置
  2. void SYS_ClkConfig(void)
  3. {
  4.         stc_sysctrl_clk_cfg_t stcCfg;
  5.  
  6.         Flash_WaitCycle(FlashWaitCycle0);//flash讀等待周期
  7.         Sysctrl_SetRCHTrim(SysctrlRchFreq24MHz);// RCH = 16MHZ
  8.         Sysctrl_SetRCLTrim(SysctrlRclFreq32768);// RCL = 32.786kHz
  9.         
  10.         ///< 選擇內部 RCH 作為HCLK時鐘源;
  11.         stcCfg.enClkSrc    = SysctrlClkRCH;// 系統(tǒng)時鐘為24Mhz
  12.         ///< HCLK SYSCLK/2
  13.         stcCfg.enHClkDiv   = SysctrlHclkDiv2; //HCLK = 12MHz
  14.         ///< PCLK 為HCLK/1
  15.         stcCfg.enPClkDiv   = SysctrlPclkDiv1;        //PCLK = 12MHz
  16.         ///< 系統(tǒng)時鐘初始化
  17.         Sysctrl_ClkInit(&stcCfg);
  18.         
  19.         //使能RCL
  20.         Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);        
  21. }
  22.  
復制代碼

總體硬件配置

  1. // 硬件處理
  2. void APP_System_Init(void)
  3. {
  4.         SYS_ClkConfig();                        // 時鐘初始化配置
  5. //        Rtc_InitConfig();                        // RTC時鐘配置
  6.         Uart0_Init();                                        // Uart初始化配置
  7. //        Lcd_ConfigRead();                        // LCD顯示配置
  8.         
  9.         ADXL345_Init();                                // ADXL345初始化
  10.         
  11. }
復制代碼


main函數(shù)

  1. int32_t main(void)
  2. {
  3.         // 硬件模塊初始化
  4.         APP_System_Init();
  5.         while(1)
  6.         {
  7.                 delay1ms(10);
  8. //Rtc_Time_Display();                // RTC時間顯示
  9.                 ADXL345_Data_collection();// ADXL345數(shù)據(jù)發(fā)送
  10.         }
  11. }
復制代碼


最終,我們可以看到如下視頻效果:

其展示姿態(tài)的軟件為 processing



最后,將代碼放到附件,供下載學習交流

  • 本文系21ic原創(chuàng),未經許可禁止轉載!

網友評論