查看: 6420|回复: 2

[经验] GD32F207ZET6驱动BMP180

[复制链接]
  • TA的每日心情
    开心
    2014-12-3 19:56
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2015-12-23 12:25:34 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 晓枫VS枯叶 于 2015-12-23 12:36 编辑

       很幸运在GD32F2系列MCU创新设计大赛的第一时间获得了GD官方送出的GD32F207ZET6开发板,看了这块板子的评测后对GD的这块芯片有了大致的了解,板载的接口相当丰富。I2C、SPI、USART这类基本的通信接口都包含在内,同时包含了CAN、USB OTG、RMII接口,这对外扩以太网、USB设备、CAN总线很方便,而多路定时器PWM互补输出、多路ADC输入以及一个RGB565接口,让小红板可以直接用在电机控制+多路模拟数据采集+中等尺寸RGB液晶显示。
            总的来说,GD32F207ZET6小红板相对于第一代GD32F150小红板可谓质的飞跃,然而任何事物都有两面,虽然小红板在接口方面是相当丰富,但是在如此小的板子上有些接口却也必须要舍弃掉,比如说可以外扩SDRAM的EXMC接口,相比STM32里的FSMC可以外扩SDRAM是一个很大的增强,相当于STM32F42X以上系列含有的FMC外设了。TLDI接口配合EXMC外扩SDRAM,对使用GUI的提升很大,但是现在是新产品用的人也不是很多。
           闲话就说到这里了,开始进入正题,利用GD32F207驱动BMP180气压计,本次主要使用的是一个I2C接口,小红板上有一个I2C2接口引出,并且注明了,如下图所示:

    1.jpg
    2.jpg
    分别是PF0、PF1,查阅数据手册和参考手册后发现,两个手册又出现了不一致,不知道以哪个作为参考
    3.jpg
    参考手册I2C2_SCL是PF0,I2C2SDA是PF1
    4.jpg
    然而到了数据手册却又反了过来
    由于I2C2引出的引脚不是默认复用的,需要打开重映射,将其映射到复用端口上。

    5.jpg
    在AFIO这一章与上面的重映射功能介绍有出现了冲突,在手册上I2C暂且发现这些所谓的“BUG”,希望大家多多反馈这些小问题,共同改善参考资料,让国产芯片更好发展。
    1. void I2C_Configuration (void)
    2. {        
    3.   GPIO_InitPara GPIO_InitStructure;
    4.   I2C_InitPara I2C_InitStructure;
    5.   RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_I2C2,ENABLE);
    6.   RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOF|RCC_APB2PERIPH_AF,ENABLE);
    7.   RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_I2C2,ENABLE);
    8.   GPIO_InitStructure.GPIO_Pin =  GPIO_PIN_0 | GPIO_PIN_1 ;
    9.   GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_OD ;
    10.   GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ ;
    11.   GPIO_Init(GPIOF, &GPIO_InitStructure) ;
    12.   GPIO_PinRemapConfig2(PCFR6,PCFR6_REMAP_I2C2_1, ENABLE);

    13.       /* Enable I2C2 */
    14.       
    15.      
    16.   I2C_InitStructure.I2C_Protocol        = I2C_PROTOCOL_I2C;
    17.   I2C_InitStructure.I2C_DutyCycle       = I2C_DUTYCYCLE_2;
    18.   I2C_InitStructure.I2C_BitRate         = 400000;
    19.   I2C_InitStructure.I2C_AddressingMode  = I2C_ADDRESSING_MODE_7BIT;
    20.   I2C_InitStructure.I2C_DeviceAddress   = 0X0A;
    21.   I2C_Init(I2C2, &I2C_InitStructure);
    22.   I2C_Enable(I2C2, ENABLE );
    23.   I2C_Acknowledge_Enable(I2C2,ENABLE);
    24. }
    复制代码
    上面是初始化I2C2的代码,还是按照手册说明重映射那两位I2C2_REMAP[1:0]=11,即GPIO_PinRemapConfig2(PCFR6,PCFR6_REMAP_I2C2_1, ENABLE);这一句,同时要打开复用时钟。
    1. s8 I2C2_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
    2. {
    3.   dev_addr=dev_addr<<1;
    4.   /* While the bus is busy */
    5.     while(I2C_GetBitState( I2C2 , I2C_FLAG_I2CBSY));

    6.     if(cnt == 2)
    7.     {
    8.         I2C_NACKPosition_Enable(I2C2,I2C_NACKPOSITION_NEXT);
    9.     }
    10.    
    11.     /* Send START condition */
    12.     I2C_StartOnBus_Enable( I2C2 , ENABLE );
    13.    
    14.     /* Test on EV5 and clear it */
    15.     while( !I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_SBSEND ));
    16.    
    17.     /* Send EEPROM address for write */
    18.     I2C_AddressingDevice_7bit( I2C2 , dev_addr, I2C_DIRECTION_TRANSMITTER );
    19.    
    20.     /* Test on EV6 and clear it */
    21.     while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND));
    22.    
    23.     /* Wait until the transmit data buffer is empty */
    24.     while( I2C_GetBitState( I2C2 , I2C_FLAG_TBE ) != SET );

    25.     /* Clear EV6 by setting again the PE bit */
    26.     I2C_Enable(I2C2, ENABLE);
    27.    
    28.     I2C_SendData(I2C2, reg_addr);
    29.    
    30.     /* Test on EV8 and clear it */
    31.     while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED));
    32.    
    33.     /* Send STRAT condition a second time */  
    34.     I2C_StartOnBus_Enable( I2C2 , ENABLE );
    35.    
    36.     /* Test on EV5 and clear it */
    37.     while( !I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_SBSEND ));
    38.    
    39.     /* Send EEPROM address for read */
    40.     I2C_AddressingDevice_7bit(I2C2, dev_addr, I2C_DIRECTION_RECEIVER);

    41.     if(cnt < 3)
    42.     {
    43.         /* Disable Acknowledgement */
    44.         I2C_Acknowledge_Enable(I2C2, DISABLE);
    45.     }
    46.    
    47.     /* Test on EV6 and clear it */
    48.     while(!I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_RECEIVER_ADDSEND ) );
    49.    
    50.     if(cnt == 1)
    51.     {
    52.         /* Send STOP Condition */
    53.         I2C_StopOnBus_Enable(I2C2, ENABLE);
    54.     }
    55.    
    56.     /* While there is data to be read */
    57.     while(cnt)  
    58.     {
    59.         if(cnt == 3)
    60.         {
    61.             /* Wait until the BTC is set */
    62.             while( I2C_GetBitState( I2C2 , I2C_FLAG_BTC ) != SET );

    63.             /* Disable Acknowledgement */
    64.             I2C_Acknowledge_Enable(I2C2, DISABLE);
    65.             
    66.         }
    67.         if(cnt == 2)
    68.         {
    69.             /* Wait until the BTC is set */
    70.             while( I2C_GetBitState( I2C2 , I2C_FLAG_BTC ) != SET );

    71.             /* Send STOP Condition */         
    72.             I2C_StopOnBus_Enable(I2C2, ENABLE);
    73.         }
    74.         
    75.         /* Test on EV7 and clear it */
    76.         if(I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_RECEIVED))  
    77.         {      
    78.             /* Read a byte from the EEPROM */
    79.             *reg_data = I2C_ReceiveData(I2C2);
    80.             
    81.             /* Point to the next location where the byte read will be saved */
    82.             reg_data++;
    83.             
    84.             /* Decrement the read bytes counter */
    85.             cnt--;
    86.         }
    87.     }

    88.     /* Enable Acknowledgement to be ready for another reception */
    89.     I2C_Acknowledge_Enable( I2C2 , ENABLE );

    90.     I2C_NACKPosition_Enable(I2C2,I2C_NACKPOSITION_CURRENT);
    91.     return 0;
    92. }
    复制代码
    上面是I2C2读数据的函数,已经封装好了,发送的设备地址是没有移位之前的7位设备地址,然后自动进行移位读取数据。
    1. s8 I2C2_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
    2. {
    3.   dev_addr=dev_addr<<1;
    4.    /* While the bus is busy */
    5.     while(I2C_GetBitState( I2C2 , I2C_FLAG_I2CBSY));
    6.    
    7.     /* Send START condition */
    8.     I2C_StartOnBus_Enable( I2C2 , ENABLE );
    9.    
    10.     /* Test on EV5 and clear it */
    11.     while(!I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_SBSEND));
    12.    
    13.     /* Test on EV6 and clear it */
    14.     I2C_AddressingDevice_7bit( I2C2 , dev_addr, I2C_DIRECTION_TRANSMITTER);
    15.    
    16.     /* Test on EV6 and clear it */
    17.     while(!I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND));
    18.    
    19.     /* Wait until the transmit data buffer is empty */
    20.     while( I2C_GetBitState( I2C2 , I2C_FLAG_TBE ) != SET );
    21.    
    22.     /* Send the EEPROM's internal address to write to */
    23.    
    24.     I2C_SendData(I2C2, reg_addr);
    25.    
    26.     /* Test on EV8 and clear it */
    27.     while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED));
    28.    
    29.     /* While there is data to be written */
    30.     while(cnt--)  
    31.     {
    32.         /* Send the current byte */
    33.         I2C_SendData(I2C2, *reg_data);
    34.         
    35.         /* Point to the next byte to be written */
    36.         reg_data++;
    37.         
    38.         /* Test on EV8 and clear it */
    39.         while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED));
    40.     }
    41.       
    42.     /* Send STOP condition */
    43.     I2C_StopOnBus_Enable( I2C2, ENABLE );
    44.     return 0;
    45. }
    复制代码
    而写函数和读函数类似,应该说比读数据函数更简单,不用转换读写状态。
    BMP180是BOSCH公司推出的一款廉价气压计,相比于MS5611气压计价格差好几倍,各项参数也是一般,测量范围在300-1100hPa,而BOSCH公司还为该芯片提供了驱动源码,直接就放在了github上,参考其中的API,替换了自己的I2C读写函数就行了。
    1. s8 BMP180_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
    2. {
    3. //        s32 iError = BMP180_INIT_VALUE;
    4. //        u8 array[I2C_BUFFER_LEN];
    5. //        u8 stringpos = BMP180_INIT_VALUE;
    6. //        array[BMP180_INIT_VALUE] = reg_addr;
    7. //        for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
    8. //                array[stringpos + C_BMP180_ONE_U8X] = *(reg_data + stringpos);
    9. //        }
    10.         /*
    11.         * Please take the below function as your reference for
    12.         * write the data using I2C communication
    13.         * "IERROR = I2C_WRITE_STRING(DEV_ADDR, ARRAY, CNT+C_BMP180_ONE_U8X)"
    14.         * add your I2C write function here
    15.         * iError is an return value of I2C read function
    16.         * Please select your valid return value
    17.         * In the driver SUCCESS defined as BMP180_INIT_VALUE
    18.     * and FAILURE defined as -C_BMP180_ONE_U8X
    19.         * Note :
    20.         * This is a full duplex operation,
    21.         * The first read data is discarded, for that extra write operation
    22.         * have to be initiated. For that cnt+C_BMP180_ONE_U8X operation done in the I2C write string function
    23.         * For more information please refer data sheet SPI communication:
    24.         */
    25.         //return (s8)iError;
    26.   return I2C2_bus_write(dev_addr,reg_addr,reg_data,cnt);
    27. }
    复制代码
    1. s8 BMP180_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
    2. {
    3. //        s32 iError = BMP180_INIT_VALUE;
    4. //        u8 array[I2C_BUFFER_LEN] = {BMP180_INIT_VALUE};
    5. //        u8 stringpos = BMP180_INIT_VALUE;
    6. //        array[BMP180_INIT_VALUE] = reg_addr;
    7. //        /* Please take the below function as your reference
    8. //         * for read the data using I2C communication
    9. //         * add your I2C rad function here.
    10. //         * "IERROR = I2C_WRITE_READ_STRING(DEV_ADDR, ARRAY, ARRAY, C_BMP180_ONE_U8X, CNT)"
    11. //         * iError is an return value of SPI write function
    12. //         * Please select your valid return value
    13. //         * In the driver SUCCESS defined as BMP180_INIT_VALUE
    14. //     * and FAILURE defined as -C_BMP180_ONE_U8X
    15. //         */
    16. //        for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
    17. //                *(reg_data + stringpos) = array[stringpos];
    18. //        }
    19. //        return (s8)iError;
    20.   return I2C2_bus_read(dev_addr,reg_addr,reg_data,cnt);
    21. }
    复制代码
    还有替换掉延时函数,同时声明#define BMP180_API,最后移位BMP180的设备地址,然后直接调用官方给出的一个demo函数就能读取温度和气压,bmp180_data_readout_template()函数。
    6.jpg
    根据手册里给出的计算海拔的公式可以大致计算所在地的海拔,计算如下所示
    1. /****************************************************************************
    2. *        This API is used to read the
    3. *        true temperature(t) value input
    4. *        parameter as uncompensated temperature(ut)
    5. *
    6. ***************************************************************************/
    7.         temperature= bmp180_get_temperature(v_uncomp_temp_u16)*0.1;

    8. /****************************************************************************
    9. *        This API is used to read the
    10. *        true pressure(p) value
    11. *        input parameter as uncompensated pressure(up)
    12. *
    13. ***************************************************************************/
    14.         pressure= bmp180_get_pressure(v_uncomp_press_u32)*1.0;
    15.         
    16.         Altitude=(44330.0*(1.0-pow(pressure/101325.0,1.0/5.255)));
    17. printf("temperature is %.1f Celsius  pressure is %.2f KPa Altitude is %.2f m\r\n",temperature,pressure/1000.0,Altitude);
    复制代码
    打印出来的数据如下:
    7.jpg
    请无视下面的乱码,直接看第一行(由于我在传输其他的数据),从墨迹天气里看到本地的气压大概是1020.0hPa和测量的数据差了200Pa,都不知道哪个是准确的,然后再谷歌地球里看到本地的海拔只有13米,然而计算出来的海拔却达到了-70多米,估计是参考基准海拔并不是1013.25hPa导致的,但是并查不到当前的海平面海拔,这样只能在后面做修正了,而温度数据还是不错的,毕竟室内开着空调,要不然呆在室外冷死,和我另外一个温度传感器测得的相差零点几摄氏度。

    忘记说了,上面的I2C接口并不在外面那一排,和飞鸟反映过了,colibri接口和ardunio完全是反过来的(就是内外排针要和上面的丝印对调)。

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-1-23 13:44
  • 签到天数: 243 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-12-23 13:13:04 | 显示全部楼层
    多谢大牛分享,,学习了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    9 小时前
  • 签到天数: 4062 天

    连续签到: 17 天

    [LV.Master]伴坛终老

    发表于 2016-3-1 16:13:06 | 显示全部楼层
    谢谢分享!
    我试着用I2C2 读写BMP280,在发送地址后,一直停留在 while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND));  不知道原因?能否给个参考程序?谢谢!
    回复 支持 反对

    使用道具 举报

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

    本版积分规则

    关闭

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



    手机版|小黑屋|与非网

    GMT+8, 2024-12-24 20:14 , Processed in 0.135980 second(s), 20 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.