首頁 > 評測 > 【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)# #技術資源#
UART簡介
通用UART模塊支持以下基本功能
■ 全雙工傳輸、半雙工傳輸、單線半雙工傳輸
■ 可編程串行通信功能
兩種字符長度:8比特、 9比特
三種校驗方式:無檢驗、奇校驗、偶校驗
三種停止長度:1比特、 2比特、 1.5比特
■ 16比特波特率發(fā)生器
■ 多機通訊
■ 硬件地址識別
■ 硬件流控
■ DMAC硬件傳輸握手
下圖為其結構框圖
我們需要對其進行初始化和一點點配置,實現(xiàn)printf打印功能,我們在這里將其配置成:
波特率:9600
停止位:1
校驗位:None
數(shù)據(jù)位:8
- void Uart0_Init(void)
- {
- Uart0_GPIO_Init();
- Uart0_Config(Value9600);
- }
- // UART0 GPIO 初始化
- void Uart0_GPIO_Init(void)
- {
- stc_gpio_cfg_t stcGpioCfg;
- DDL_ZERO_STRUCT(stcGpioCfg);
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);//開啟GPIO外設時鐘
- //TX
- stcGpioCfg.enDir = GpioDirOut;
- Gpio_Init(UART0_TX_PORT, UART0_TX_PIN, &stcGpioCfg);
- Gpio_SetAfMode(UART0_TX_PORT, UART0_TX_PIN, GpioAf2);
- //RX
- stcGpioCfg.enDir = GpioDirIn;
- Gpio_Init(UART0_RX_PORT, UART0_RX_PIN, &stcGpioCfg);
- Gpio_SetAfMode(UART0_RX_PORT, UART0_RX_PIN, GpioAf2);
- }
- //Uart0 配置
- void Uart0_Config(uint32_t BaudRate)
- {
- stc_uart_cfg_t stcUartCfg;
- DDL_ZERO_STRUCT(stcUartCfg);
- // 先禁止接收中斷
- EnableNvic(UART0_2_IRQn, IrqLevel3, FALSE);
- Uart_DisableIrq(M0P_UART0, UartRxIrq);
- Sysctrl_SetPeripheralGate(SysctrlPeripheralUart0,TRUE);//開啟Uart0外設時鐘
- stcUartCfg.enRunMode = UartMskMode1;//模式1
- stcUartCfg.enStopBit = UartMsk1bit;//1位停止位
- switch(BaudRate)
- {
- case Value1200: stcUartCfg.stcBaud.u32Baud = 1200; break;
- case Value2400: stcUartCfg.stcBaud.u32Baud = 2400; break;
- case Value4800: stcUartCfg.stcBaud.u32Baud = 4800; break;
- case Value9600: stcUartCfg.stcBaud.u32Baud = 9600; break;
- case Value19200: stcUartCfg.stcBaud.u32Baud = 19200; break;
- case Value38400: stcUartCfg.stcBaud.u32Baud = 38400; break;
- case Value57600: stcUartCfg.stcBaud.u32Baud = 57600; break;
- case Value115200: stcUartCfg.stcBaud.u32Baud = 115200; break;
- }
- stcUartCfg.stcBaud.enClkDiv = UartMsk8Or16Div;//8分頻
- stcUartCfg.stcBaud.u32Pclk = Sysctrl_GetPClkFreq();
- Uart_Init(M0P_UART0, &stcUartCfg);
- // 再開啟中斷
- Uart_ClrStatus(M0P_UART0, UartRC);
- Uart_EnableIrq(M0P_UART0,UartRxIrq);//接收中斷
- EnableNvic(UART0_2_IRQn, IrqLevel3, TRUE);
- }
- int fputc(int ch, FILE *f) //重定向printf函數(shù)到uart0串口打印
- {
- (void)f;//防止編譯報警告
- Uart_SendDataPoll(M0P_UART0, (uint8_t)ch);
- return ch;
- }
IIC簡介
HC32L96PCTA的I2C控制器支持以下特性:
■ 支持主機發(fā)送/接收,從機發(fā)送/接收四種工作模式
■ 支持標準(100Kbps) / 快速(400Kbps) / 高速(1Mbps) 三種工作速率
■ 支持7位尋址功能
■ 支持噪聲過濾功能
■ 支持廣播地址
■ 支持中斷狀態(tài)查詢功能
由于我們這里只有一個從機設備(其地址為0x53),因此用到的IIC功能其實用軟件模擬也能實現(xiàn),當然這里由于是測評,用的是硬件驅動。
其初始化代碼如下:
- #define MyIIC_SCL_PORT (GpioPortB)
- #define MyIIC_SCL_PIN (GpioPin8)
- #define MyIIC_SDA_PORT (GpioPortB)
- #define MyIIC_SDA_PIN (GpioPin9)
- // IO端口配置
- static void MyIIC_PortCfg(void)
- {
- stc_gpio_cfg_t stcGpioCfg;
- DDL_ZERO_STRUCT(stcGpioCfg);
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //開啟GPIO時鐘門控
- stcGpioCfg.enDir = GpioDirOut; ///< 端口方向配置->輸出
- stcGpioCfg.enOD = GpioOdEnable; ///< 開漏輸出
- stcGpioCfg.enPu = GpioPuEnable; ///< 端口上拉配置->使能
- stcGpioCfg.enPd = GpioPdDisable; ///< 端口下拉配置->禁止
- stcGpioCfg.bOutputVal = TRUE;
- Gpio_Init(MyIIC_SCL_PORT,MyIIC_SCL_PIN,&stcGpioCfg); ///< 端口初始化
- Gpio_Init(MyIIC_SDA_PORT,MyIIC_SDA_PIN,&stcGpioCfg);
- Gpio_SetAfMode(MyIIC_SCL_PORT,MyIIC_SCL_PIN,GpioAf1); ///< 配置PB08為SCL
- Gpio_SetAfMode(MyIIC_SDA_PORT,MyIIC_SDA_PIN,GpioAf1); ///< 配置PB09為SDA
- }
- // I2C 模塊配置
- void MyI2c_Config(void)
- {
- stc_i2c_cfg_t stcI2cCfg;
- DDL_ZERO_STRUCT(stcI2cCfg); ///< 初始化結構體變量的值為0
- Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c0,TRUE); ///< 開啟I2C0時鐘門控
- stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq(); ///< 獲取PCLK時鐘
- stcI2cCfg.u32Baud = 100000; ///< 100kHz
- stcI2cCfg.enMode = I2cMasterMode; ///< 主機模式
- stcI2cCfg.u8SlaveAddr = IIC_ADDR; ///< 從地址,主模式無效
- stcI2cCfg.bGc = FALSE; ///< 廣播地址應答使能關閉
- I2C_Init(M0P_I2C0,&stcI2cCfg); ///< 模塊初始化
- MyIIC_PortCfg();// GPIO口配置
- delay1ms(2);
- I2C_SetFunc(M0P_I2C0,I2cStart_En); //開始信號
- }
在初始化完成后,就根據(jù)例程中提供的數(shù)據(jù)讀取和寫入函數(shù),進行簡單的修改:
- /**
- ******************************************************************************
- ** \brief 主機接收函數(shù)
- **
- ** \param REGAddr從機寄存器地址,pu8Data讀數(shù)據(jù)存放緩存,u32Len讀數(shù)據(jù)長度
- **
- ** \retval 讀數(shù)據(jù)是否成功
- **
- ******************************************************************************/
- en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data,uint32_t u32Len,uint8_t REGAddr)
- {
- en_result_t enRet = Error;
- uint8_t u8i=0,u8State;
- I2C_SetFunc(I2CX,I2cStart_En);
- while(1)
- {
- while(0 == I2C_GetIrq(I2CX))
- {;}
- u8State = I2C_GetState(I2CX);
- switch(u8State)
- {
- case 0x08: //已發(fā)送起始條件,將發(fā)送SLA+R
- I2C_ClearFunc(I2CX,I2cStart_En);
- I2C_WriteByte(I2CX,IIC_WRITE_ADDR); //發(fā)送SLA+W
- break;
- case 0x18: //已發(fā)送SLA+W,并接收到ACK
- I2C_WriteByte(I2CX,REGAddr); //發(fā)送寄存器地址
- break;
- case 0x28: //已發(fā)送數(shù)據(jù),接收到ACK
- I2C_SetFunc(I2CX,I2cStart_En);
- break;
- case 0x10: //已發(fā)送重復起始條件
- I2C_ClearFunc(I2CX,I2cStart_En);
- I2C_WriteByte(I2CX,IIC_READ_ADDR); //讀命令發(fā)送
- break;
- case 0x40: //已發(fā)送SLA+R,并接收到ACK
- if(u32Len>1)
- {
- I2C_SetFunc(I2CX,I2cAck_En);
- }
- break;
- case 0x50: //已接收數(shù)據(jù)字節(jié),并已返回ACK信號
- pu8Data[u8i++] = I2C_ReadByte(I2CX);
- if(u8i==u32Len-1)
- {
- I2C_ClearFunc(I2CX,I2cAck_En); //讀數(shù)據(jù)時,倒數(shù)第二個字節(jié)ACK關閉
- }
- break;
- case 0x58: //已接收到最后一個數(shù)據(jù),NACK已返回
- pu8Data[u8i++] = I2C_ReadByte(I2CX);
- I2C_SetFunc(I2CX,I2cStop_En); //發(fā)送停止條件
- break;
- case 0x38: //在發(fā)送地址或數(shù)據(jù)時,仲裁丟失
- I2C_SetFunc(I2CX,I2cStart_En); //當總線空閑時發(fā)起起始條件
- break;
- case 0x48: //發(fā)送SLA+R后,收到一個NACK
- I2C_SetFunc(I2CX,I2cStop_En);
- I2C_SetFunc(I2CX,I2cStart_En);
- break;
- default: //其他錯誤狀態(tài),重新發(fā)送起始條件
- I2C_SetFunc(I2CX,I2cStart_En); //其他錯誤狀態(tài),重新發(fā)送起始條件
- break;
- }
- I2C_ClearIrq(I2CX); //清除中斷狀態(tài)標志位
- if(u8i==u32Len) //數(shù)據(jù)全部讀取完成,跳出while循環(huán)
- {
- break;
- }
- }
- enRet = Ok;
- return enRet;
- }
- /**
- ******************************************************************************
- ** \brief 主機發(fā)送函數(shù)
- **
- ** \param REGAddr從機寄存器地址,pu8Data寫數(shù)據(jù),u32Len寫數(shù)據(jù)長度,REGAddr操作寄存器地址
- **
- ** \retval 寫數(shù)據(jù)是否成功
- **
- ******************************************************************************/
- en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data,uint32_t u32Len,uint8_t REGAddr)
- {
- en_result_t enRet = Error;
- uint8_t u8i=0,u8State,u8Flag=FALSE;
- I2C_SetFunc(I2CX,I2cStart_En);
- while(1)
- {
- while(0 == I2C_GetIrq(I2CX))
- {;}
- u8State = I2C_GetState(I2CX);
- switch(u8State)
- {
- case 0x08: ///已發(fā)送起始條件
- I2C_ClearFunc(I2CX,I2cStart_En);
- I2C_WriteByte(I2CX,IIC_WRITE_ADDR); ///從設備地址發(fā)送
- break;
- case 0x18: ///已發(fā)送SLA+W,并接收到ACK
- I2C_WriteByte(I2CX,REGAddr);
- break;
- case 0x28: ///上一次發(fā)送數(shù)據(jù)后接收到ACK
- if (u8i < u32Len)
- {
- I2C_WriteByte(I2CX,pu8Data[u8i++]); ///< 繼續(xù)發(fā)送數(shù)據(jù)
- }
- else
- {
- I2C_SetFunc(I2CX,I2cStop_En); ///< 出停止條件
- u8Flag = TRUE;
- }
- break;
- case 0x20: ///上一次發(fā)送SLA+W后,收到NACK
- break;
- case 0x38: ///上一次在SLA+讀或寫時丟失仲裁
- I2C_SetFunc(I2CX,I2cStart_En); ///當I2C總線空閑時發(fā)送起始條件
- break;
- case 0x30: ///已發(fā)送I2Cx_DATA中的數(shù)據(jù),收到NACK,將傳輸一個STOP條件
- I2C_SetFunc(I2CX,I2cStop_En); ///發(fā)送停止條件
- break;
- default:
- break;
- }
- I2C_ClearIrq(I2CX); ///清除中斷狀態(tài)標志位
- if(u8Flag == TRUE) ///< 數(shù)據(jù)發(fā)送完成
- {
- break;
- }
- }
- enRet = Ok;
- return enRet;
- }
自此,我們初步完成了I2C的初始化。
ADXL345簡介
一款加速度計,就不多介紹了,主要檢測其芯體在空間中X、Y、Z軸的數(shù)據(jù)在此,對其進行初始化和數(shù)據(jù)的采集
- //ADXL345設置偏移量
- void ADXL345_SetOffset(char xOffset, char yOffset, char zOffset)
- {
- union
- {
- unsigned char u8t;// 無符號
- char q8t;// 有符號
- }X_Offset;
- union
- {
- unsigned char u8t;// 無符號
- char q8t;// 有符號
- }Y_Offset;
- union
- {
- unsigned char u8t;// 無符號
- char q8t;// 有符號
- }Z_Offset;
- X_Offset.q8t = xOffset;
- Y_Offset.q8t = yOffset;
- Z_Offset.q8t = zOffset;
- I2C_MasterWriteData(M0P_I2C0, &X_Offset.u8t, 1, ADXL345_OFSX);
- I2C_MasterWriteData(M0P_I2C0, &Y_Offset.u8t, 1, ADXL345_OFSY);
- I2C_MasterWriteData(M0P_I2C0, &Z_Offset.u8t, 1, ADXL345_OFSZ);
- }
數(shù)據(jù)初始化
- //ADXL345初始化配置
- void ADXL345_Init(void)
- {
- MyI2c_Config();
- delay1ms(10);
- if(ADXL345_InitFlag==0)
- {
- ADXL345_Ready();//ADXL345初始化配置
- }
- }
- //ADXL345準備初始化
- void ADXL345_Ready(void)
- {
- I2C_MasterReadData(M0P_I2C0, ADXL345_Buffer, 1, ADXL345_DEVID);
- delay1ms(2);
- if(ADXL345_Buffer[0]==0xE5)//ADXL345的器件ID為0xE5
- {
- ADXL345_Buffer[0] = 0x08;
- I2C_MasterWriteData(M0P_I2C0, ADXL345_Buffer, 1, ADXL345_POWER_CTL);
- delay1ms(3);
- ADXL345_SetOffset((char)4,(char)0,(char)-7);//設置三個軸偏移量
- ADXL345_InitFlag = 1;
- }
- else//加速度傳感器壞
- {
- ADXL345_InitFlag = 0;
- }
- }
數(shù)據(jù)采集處理打印輸出,需要對其進行數(shù)據(jù)轉換和濾波
- //ADXL345的X,Y,Z軸數(shù)據(jù)讀取
- void ADXL345_GetXYZValue(float *x, float *y, float *z)
- {
- float X_Temp=0,Y_Temp=0,Z_Temp=0;
- I2C_MasterReadData(M0P_I2C0, ADXL345_Buffer, 6, ADXL345_DATAX0);
- X_Temp += (float)((short)(ADXL345_Buffer[1] << 8) + ADXL345_Buffer[0])/256;//數(shù)據(jù)組合再除以256(即轉換為g為單位)
- Y_Temp += (float)((short)(ADXL345_Buffer[3] << 8) + ADXL345_Buffer[2])/256;
- Z_Temp += (float)((short)(ADXL345_Buffer[5] << 8) + ADXL345_Buffer[4])/256;
- *x = X_Temp;
- *y = Y_Temp;
- *z = Z_Temp;
- }
- //ADXL345數(shù)據(jù)收集,處理,輸出
- void ADXL345_Data_collection(void)
- {
- float X_out = 0.0;
- float Y_out = 0.0;
- float Z_out = 0.0;
- float roll = 0.0;
- float pitch = 0.0;
- if(ADXL345_InitFlag==1)//ADXL345初始化成功了
- {
- delay1ms(10);
- ADXL345_GetXYZValue(&X_out, &Y_out, &Z_out);
- roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
- pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;
- // Low-pass filter
- rollF = 0.94 * rollF + 0.06 * roll;
- pitchF = 0.94 * pitchF + 0.06 * pitch;
- printf("%.2f/%.2f\r\n",rollF, pitchF);
- }
- else
- {
- printf("ADXL345 Failure !!!");
- }
- }
而后,在main函數(shù)中對其進行調用時鐘配置(和上期一樣)
- // 系統(tǒng)時鐘配置
- void SYS_ClkConfig(void)
- {
- stc_sysctrl_clk_cfg_t stcCfg;
- Flash_WaitCycle(FlashWaitCycle0);//flash讀等待周期
- Sysctrl_SetRCHTrim(SysctrlRchFreq24MHz);// RCH = 16MHZ
- Sysctrl_SetRCLTrim(SysctrlRclFreq32768);// RCL = 32.786kHz
- ///< 選擇內部 RCH 作為HCLK時鐘源;
- stcCfg.enClkSrc = SysctrlClkRCH;// 系統(tǒng)時鐘為24Mhz
- ///< HCLK SYSCLK/2
- stcCfg.enHClkDiv = SysctrlHclkDiv2; //HCLK = 12MHz
- ///< PCLK 為HCLK/1
- stcCfg.enPClkDiv = SysctrlPclkDiv1; //PCLK = 12MHz
- ///< 系統(tǒng)時鐘初始化
- Sysctrl_ClkInit(&stcCfg);
- //使能RCL
- Sysctrl_ClkSourceEnable(SysctrlClkRCL, TRUE);
- }
總體硬件配置
- // 硬件處理
- void APP_System_Init(void)
- {
- SYS_ClkConfig(); // 時鐘初始化配置
- // Rtc_InitConfig(); // RTC時鐘配置
- Uart0_Init(); // Uart初始化配置
- // Lcd_ConfigRead(); // LCD顯示配置
- ADXL345_Init(); // ADXL345初始化
- }
main函數(shù)
- int32_t main(void)
- {
- // 硬件模塊初始化
- APP_System_Init();
- while(1)
- {
- delay1ms(10);
- //Rtc_Time_Display(); // RTC時間顯示
- ADXL345_Data_collection();// ADXL345數(shù)據(jù)發(fā)送
- }
- }
最終,我們可以看到如下視頻效果:
其展示姿態(tài)的軟件為 processing
最后,將代碼放到附件,供下載學習交流
- 本文系21ic原創(chuàng),未經許可禁止轉載!
網友評論
- 聯(lián)系人:巧克力娃娃
- 郵箱:board@21ic.com
- 我要投稿
-
歡迎入駐,開放投稿
-
人均百萬?英偉達中國員工收入曝光! 2024-08-29
-
《黑神話:悟空》玩家硬盤升級攻略:提升游戲體驗,暢享3A大作 2024-08-29
-
數(shù)睿數(shù)據(jù)參加《系統(tǒng)與軟件工程 低代碼開發(fā)平臺通用技術要求》國家標準編制 2024-08-29
- NRF52810藍牙數(shù)字耳機找人定制
預算:¥30005天前
- 125KW模塊式PCS軟硬件外包開發(fā)
預算:¥1100000015小時前
- 12V汽車啟動電源項目BMS設計
預算:¥50000023小時前
- 數(shù)據(jù)可視化軟件 開發(fā)
預算:¥5000023小時前
- PLC項目調試修改
預算:¥100001天前
- 起動電機控制器開發(fā)
預算:¥1100001天前