[方案相关]【HC32L96PCTA测评】+UART+IIC测评

UART简介
通用UART模块支持以下基本功能
■ 全双工传输、半双工传输、单线半双工传输
■ 可编程串行通信功能
     两种字符长度:8比特、 9比特
     三种校验方式:无检验、奇校验、偶校验
     三种停止长度:1比特、 2比特、 1.5比特
■ 16比特波特率发生器
■ 多机通讯
■ 硬件地址识别
■ 硬件流控
■ DMAC硬件传输握手

下图为其结构框图
 


我们需要对其进行初始化和一点点配置,实现printf打印功能,我们在这里将其配置成:
波特率:9600
停止位:1
校验位:None
数据位: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函数到uart0串口打印

{

        (void)f;//防止编译报警告

        Uart_SendDataPoll(M0P_UART0, (uint8_t)ch);

        return ch;

}

IIC简介
HC32L96PCTA的I2C控制器支持以下特性:
■ 支持主机发送/接收,从机发送/接收四种工作模式
■ 支持标准(100Kbps) / 快速(400Kbps) / 高速(1Mbps) 三种工作速率
■ 支持7位寻址功能
■ 支持噪声过滤功能
■ 支持广播地址
■ 支持中断状态查询功能

由于我们这里只有一个从机设备(其地址为0x53),因此用到的IIC功能其实用软件模拟也能实现,当然这里由于是测评,用的是硬件驱动。
其初始化代码如下:

复制
#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);                                                  //开始信号

}

在初始化完成后,就根据例程中提供的数据读取和写入函数,进行简单的修改:

复制
/**

 ******************************************************************************

 ** \brief  主机接收函数

 **

 ** \param REGAddr从机寄存器地址,pu8Data读数据存放缓存,u32Len读数据长度

 **

 ** \retval 读数据是否成功

 **

 ******************************************************************************/

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:                                    //已发送起始条件,将发送SLA+R

                I2C_ClearFunc(I2CX,I2cStart_En);

                I2C_WriteByte(I2CX,IIC_WRITE_ADDR);                                //发送SLA+W

                break;

            case 0x18:                                    //已发送SLA+W,并接收到ACK

                I2C_WriteByte(I2CX,REGAddr);              //发送寄存器地址

                break;

            case 0x28:                                    //已发送数据,接收到ACK

                I2C_SetFunc(I2CX,I2cStart_En);

                break;

            case 0x10:                                    //已发送重复起始条件

                I2C_ClearFunc(I2CX,I2cStart_En);

                I2C_WriteByte(I2CX,IIC_READ_ADDR);                                //读命令发送

                break;

            case 0x40:                                    //已发送SLA+R,并接收到ACK

                if(u32Len>1)

                {

                    I2C_SetFunc(I2CX,I2cAck_En);

                }

                break;

            case 0x50:                                    //已接收数据字节,并已返回ACK信号

                pu8Data[u8i++] = I2C_ReadByte(I2CX);

                if(u8i==u32Len-1)

                {

                    I2C_ClearFunc(I2CX,I2cAck_En);        //读数据时,倒数第二个字节ACK关闭

                }

                break;

            case 0x58:                                    //已接收到最后一个数据,NACK已返回

                pu8Data[u8i++] = I2C_ReadByte(I2CX);

                I2C_SetFunc(I2CX,I2cStop_En);             //发送停止条件

                break;    

            case 0x38:                                    //在发送地址或数据时,仲裁丢失

                I2C_SetFunc(I2CX,I2cStart_En);            //当总线空闲时发起起始条件

                break;

            case 0x48:                                    //发送SLA+R后,收到一个NACK

                I2C_SetFunc(I2CX,I2cStop_En);

                I2C_SetFunc(I2CX,I2cStart_En);

                break;

            default:                                      //其他错误状态,重新发送起始条件

                I2C_SetFunc(I2CX,I2cStart_En);            //其他错误状态,重新发送起始条件

                break;

        }

        I2C_ClearIrq(I2CX);                               //清除中断状态标志位

        if(u8i==u32Len)                                   //数据全部读取完成,跳出while循环

        {

            break;

        }

    }

    enRet = Ok;

    return enRet;

}
复制
/**

 ******************************************************************************

 ** \brief  主机发送函数

 **

 ** \param REGAddr从机寄存器地址,pu8Data写数据,u32Len写数据长度,REGAddr操作寄存器地址

 **

 ** \retval 写数据是否成功

 **

 ******************************************************************************/

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:                                 ///已发送起始条件

                I2C_ClearFunc(I2CX,I2cStart_En);

                I2C_WriteByte(I2CX,IIC_WRITE_ADDR);          ///从设备地址发送

                break;

            case 0x18:                                 ///已发送SLA+W,并接收到ACK

                                                                I2C_WriteByte(I2CX,REGAddr);

                                                                break;

            case 0x28:                                 ///上一次发送数据后接收到ACK

                if (u8i < u32Len)

                {

                    I2C_WriteByte(I2CX,pu8Data[u8i++]);  ///< 继续发送数据

                }

                                                                else

                {

                    I2C_SetFunc(I2CX,I2cStop_En);     ///< 出停止条件

                    u8Flag = TRUE;

                }

                                                                break;

            case 0x20:                                 ///上一次发送SLA+W后,收到NACK

                                                                break;

            case 0x38:                                 ///上一次在SLA+读或写时丢失仲裁

                I2C_SetFunc(I2CX,I2cStart_En);         ///当I2C总线空闲时发送起始条件

                break;

            case 0x30:                                 ///已发送I2Cx_DATA中的数据,收到NACK,将传输一个STOP条件

                I2C_SetFunc(I2CX,I2cStop_En);          ///发送停止条件

                break;

            default:

                break;

        }            

        I2C_ClearIrq(I2CX);                            ///清除中断状态标志位

        if(u8Flag == TRUE)  ///< 数据发送完成

        {   

            break;

        }

    }

    enRet = Ok;

    return enRet;

}

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

ADXL345简介
一款加速度计,就不多介绍了,主要检测其芯体在空间中X、Y、Z轴的数据在此,对其进行初始化和数据的采集

复制
//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);

        

}

数据初始化

复制
//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;

        }

}

数据采集处理打印输出,需要对其进行数据转换和滤波

复制
//ADXL345的X,Y,Z轴数据读取

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;//数据组合再除以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数据收集,处理,输出

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函数中对其进行调用时钟配置(和上期一样)

复制
// 系统时钟配置

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;// 系统时钟为24Mhz

        ///< HCLK SYSCLK/2

        stcCfg.enHClkDiv   = SysctrlHclkDiv2; //HCLK = 12MHz 

        ///< PCLK 为HCLK/1

        stcCfg.enPClkDiv   = SysctrlPclkDiv1;        //PCLK = 12MHz

        ///< 系统时钟初始化

        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函数

复制
int32_t main(void)

{

        // 硬件模块初始化

        APP_System_Init();

        while(1)

        {

                delay1ms(10);

//Rtc_Time_Display();                // RTC时间显示

                ADXL345_Data_collection();// ADXL345数据发送

        }

}


最终,我们可以看到如下视频效果:

其展示姿态的软件为 processing
---------------------
作者:hulai123456
链接:https://bbs.21ic.com/icview-3324434-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值