2回答

1收藏

[分享] GD32F207ZET6驱动BMP180

GD32 GD32 7473 人阅读 | 2 人回复 | 2015-12-23

本帖最后由 晓枫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接口引出,并且注明了,如下图所示:



分别是PF0、PF1,查阅数据手册和参考手册后发现,两个手册又出现了不一致,不知道以哪个作为参考

参考手册I2C2_SCL是PF0,I2C2SDA是PF1

然而到了数据手册却又反了过来
由于I2C2引出的引脚不是默认复用的,需要打开重映射,将其映射到复用端口上。


在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()函数。

根据手册里给出的计算海拔的公式可以大致计算所在地的海拔,计算如下所示
  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);
复制代码
打印出来的数据如下:

请无视下面的乱码,直接看第一行(由于我在传输其他的数据),从墨迹天气里看到本地的气压大概是1020.0hPa和测量的数据差了200Pa,都不知道哪个是准确的,然后再谷歌地球里看到本地的海拔只有13米,然而计算出来的海拔却达到了-70多米,估计是参考基准海拔并不是1013.25hPa导致的,但是并查不到当前的海平面海拔,这样只能在后面做修正了,而温度数据还是不错的,毕竟室内开着空调,要不然呆在室外冷死,和我另外一个温度传感器测得的相差零点几摄氏度。

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

分享到:
回复

使用道具 举报

回答|共 2 个

倒序浏览

沙发

Paderboy

发表于 2015-12-23 13:13:04 | 只看该作者

多谢大牛分享,,学习了
板凳

hjf2002

发表于 2016-3-1 16:13:06 | 只看该作者

谢谢分享!
我试着用I2C2 读写BMP280,在发送地址后,一直停留在 while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND));  不知道原因?能否给个参考程序?谢谢!
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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