查看: 4631|回复: 0

【飞凌RT1052】SYSTICK计时器&DHT11温湿度传感器&RTC&TRNG综合实验

[复制链接]
  • TA的每日心情
    开心
    2018-4-20 15:04
  • 签到天数: 8 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    49

    主题

    188

    帖子

    1

    金牌会员

    Rank: 6Rank: 6

    积分
    3265
    最后登录
    2023-7-24
    发表于 2018-11-25 01:22:24 | 显示全部楼层 |阅读模式
    【飞凌RT1052】SYSTICK计时器&DHT11温湿度传感器&RTC&TRNG综合实验
        本文涉及到外设:SYSTICK,LPI2C,TRNG。
        绝大部分的传感器都是串行通信,而串行通信根据协议又分为单总线 I2C SPI UART四种,而异步单串行总线和I2C总线通信在单片机项目中用得非常多,加上NXP本身拥有国际标准I2C通信协议的修改、发布、推广权,因此NXP的单片机中都集成了非常好用的硬件LPI2C接口,可根据I2C从机的情况修改通信速率、数据位、有无ack握手信令等参数。
        在RT1052的官方SDK中,LPI2C例程是针对板上的RTC即实时日历时钟芯片RX8010和一片EEPROM,EEPROM不做多余研究,只研究项目中需要用到的RX8010芯片:


    只需要做出LPI2C的初始化之后就可以用这个接口了:


            lpi2c_master_config_t masterConfig = {0};
            LPI2C_MasterGetDefaultConfig(&masterConfig);
              masterConfig.baudRate_Hz = baud;
              LPI2C_MasterInit(LPI2C1, &masterConfig,CLOCK_GetFreq(kCLOCK_Usb1PllClk)/48);


            IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL,1);
            IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA,1);
            IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL,0xD8B0u);
              IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA,0xD8B0u);  


    单片机设置LPI2C模式为主机模式,设置LPI2C时钟为USBPLL时钟的48分频,引脚复用号为1,配置模式为0xD8B0u,即开漏。


    LPI2C读写传输的函数就更简单了:


    status_t LPI2C1_Write(LPI2C_Type *base,unsigned char addr,int subAdd,unsigned char *dataBuff,uint16_t dataLen)
    {
        lpi2c_master_transfer_t xfer;
        status_t status;


        xfer.slaveAddress = addr;
        xfer.direction = kLPI2C_Write;
        xfer.subaddress = subAdd;
        xfer.subaddressSize = 0x01;
        xfer.data = dataBuff;
        xfer.dataSize = dataLen;
        xfer.flags = kLPI2C_TransferDefaultFlag;


        status = LPI2C_MasterTransferBlocking(base,&xfer);


        return status;
    }


    int LPI2C1_Read(LPI2C_Type *base,unsigned char addr,int subAdd,unsigned char* dataBuffer, uint16_t dataLen)
    {
            lpi2c_master_transfer_t masterXfer = {0};
            status_t reVal = kStatus_Fail;


            masterXfer.slaveAddress = addr;
            masterXfer.direction = kLPI2C_Read;
            masterXfer.subaddress = subAdd;
            masterXfer.subaddressSize = 0x01;
            masterXfer.data = dataBuffer;
            masterXfer.dataSize = dataLen;
            masterXfer.flags = kLPI2C_TransferDefaultFlag;


            reVal =LPI2C_MasterTransferBlocking(base,&masterXfer);


            if (reVal!=kStatus_Success)
                            return 1;
           
            return 0;
    }


    只需要指定从机地址slaveAddress,读写寄存器起始地址subaddress,读写方向direction,读写长度subaddressSize,然后传入unsigned char类型的数组作为读写数据载体就完事了,非常简单。


    由于官方操作RX8010的函数可读性不高,因此我封装成了直接读写年、月、日、时、分、秒的函数,以形参列表按序传入即可,这种所有操作封装起来的函数,比较符合我的代码风格:


    int RX8010_Set_Time(unsigned char year,unsigned char month,unsigned char date,unsigned char hour,
    unsigned char minute,unsigned char sec)
    {
            unsigned char y,m,d,h,mi,s;
            y=Byte_2_BCD(year/10,year%10);
            LPI2C1_Write(LPI2C1,RX8010_ADDR,RX8010_YEAR,&y,1);
           
            if(month<1||month>12)
                    return 1;
            m=Byte_2_BCD(month/10,month%10);
            LPI2C1_Write(LPI2C1,RX8010_ADDR,RX8010_MONTH,&m,1);
           
            if(date<1||date>31)
                    return 2;
            d=Byte_2_BCD(date/10,date%10);
            LPI2C1_Write(LPI2C1,RX8010_ADDR,RX8010_MDAY,&d,1);
           
            if(hour<0||hour>24)
                    return 3;
            h=Byte_2_BCD(hour/10,hour%10);
            LPI2C1_Write(LPI2C1,RX8010_ADDR,RX8010_HOUR,&h,1);
           
            if(minute<0||minute>60)
                    return 4;
            mi=Byte_2_BCD(minute/10,minute%10);
            LPI2C1_Write(LPI2C1,RX8010_ADDR,RX8010_MIN,&mi,1);
           
            if(sec<0||sec>60)
                    return 5;
            s=Byte_2_BCD(sec/10,sec%10);
            LPI2C1_Write(LPI2C1,RX8010_ADDR,RX8010_SEC,&s,1);
           
            return 0;
    }


    int RX8010_Get_Time()
    {
        unsigned char date[7],dateRsul[7],flagreg;


        LPI2C1_Read(LPI2C1,RX8010_ADDR,RX8010_FLAG,&flagreg,1);


        if (flagreg & RX8010_FLAG_VLF)
                            {
            return 1;
          }


        LPI2C1_Read(LPI2C1,RX8010_ADDR,RX8010_SEC,date,7);


                    dateRsul[0] = BCD_2_Byte(date[RX8010_SEC - RX8010_SEC] & 0x7f);
        dateRsul[1] = BCD_2_Byte(date[RX8010_MIN - RX8010_SEC] & 0x7f);
        dateRsul[2] = BCD_2_Byte(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
        dateRsul[4] = BCD_2_Byte(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
        dateRsul[5] = BCD_2_Byte(date[RX8010_MONTH - RX8010_SEC] & 0x1f);
        dateRsul[6] = BCD_2_Byte(date[RX8010_YEAR - RX8010_SEC]);
                    dateRsul[3] = date[RX8010_WDAY - RX8010_SEC] & 0x7f;


        printf("\r\n Read datetime from RX8010:    20%d%d-%d%d-%d%d  %d%d:%d%d:%d%d   \r\n",
        dateRsul[6]/10,dateRsul[6]%10,dateRsul[5]/10,dateRsul[5]%10,dateRsul[4]/10,dateRsul[4]%10,
                    dateRsul[2]/10,dateRsul[2]%10,dateRsul[1]/10,dateRsul[1]%10,dateRsul[0]/10,dateRsul[0]%10);
                    return 0;
    }


    在主程序中初始化一个确定的时间即可开始循环采集:
            LPI2C1_Init(100000);
            RX8010_Set_Time(18,11,25,0,23,0);




    while(1)
    {
    ...
            if(RX8010_Get_Time()==0)
            printf("20%d-%d-%d %d:%d:%d\n\n",year,month,mdate,hour,min,sec);
    ...
    }


    然后是DHT11,要使用DHT11必须先有精确延时微秒的函数,此处使用SYSTICK计时器实现阻塞延时:


    int fac_us;
    void Delay_Init(int sysclk)
    {
            fac_us=sysclk;
            SysTick->CTRL|=SysTick_CTRL_CLKSOURCE_Msk;
            SysTick->LOAD=16777215;       
            SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;


    }                       


    设置系统计数值600,即主频。


    void Delay_us(int nus)
    {               
            int ticks,told,tnow,tcnt=0,reload=SysTick->LOAD;
            ticks=nus*fac_us;
            told=SysTick->VAL;
            while(1)
            {
                    tnow=SysTick->VAL;       
                    if(tnow!=told)
                    {            
                            if(tnow<told)tcnt+=told-tnow;
                            else tcnt+=reload-tnow+told;            
                            told=tnow;
                            if(tcnt>=ticks)break;       
                    }  
            }
    }
    此处是使用阻塞延时方式。


    连接DHT11到板上的GPIO1_24引脚,即8针KEY接口的第一针,供电采用SWD调试接口那边的3V3:
    IMG_20181125_005532R.jpg


    然后参考网上的DHT11例程,配置好GPIO之后即可使用:
    unsigned char DHT11_Read_Data(unsigned char *temp,unsigned char *humi)   
    {        
            unsigned char buf[5];
            unsigned char i;
            DHT11_Rst();
            if(DHT11_Check()==0)
            {
                    for(i=0;i<5;i++)
                    {
                            buf=DHT11_Read_Byte();
                    }
                    if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
                    {
                            *humi=buf[0];
                            *temp=buf[2];
                    }
            }
            else return 1;
            return 0;            
    }


    最后是随机数发生器TRNG,这个我只是用来测试的,后面的项目会用到,随机生成480个【0,271】范围内的随机正整数并在RGB液晶屏上显示出来:
            int a[480];
           
            trng_config_t trngConfig;
            TRNG_GetDefaultConfig(&trngConfig);
            trngConfig.sampleMode = kTRNG_SampleModeVonNeumann;
            TRNG_Init(TRNG,&trngConfig);
            TRNG_GetRandomData(TRNG,a,480);
            for(i=0;i<480;i++)
            {
                    if(a<0)a=-a;
                            a=a%(272-1+1)+1;
                            ELCDIF_RGB_DrawVLine(i,272-a,a,0xffff);
            }


    观察效果:
    IMG_20181125_010149R.jpg 43.jpg 44.jpg
    工程文件:
    工程.zip (1.24 MB, 下载次数: 6)
    42.jpg
    今天心情不错
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-19 03:48 , Processed in 0.090098 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表