TA的每日心情 | 开心 2014-12-3 19:56 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到
|
本帖最后由 晓枫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”,希望大家多多反馈这些小问题,共同改善参考资料,让国产芯片更好发展。- void I2C_Configuration (void)
- {
- GPIO_InitPara GPIO_InitStructure;
- I2C_InitPara I2C_InitStructure;
- RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_I2C2,ENABLE);
- RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOF|RCC_APB2PERIPH_AF,ENABLE);
- RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_I2C2,ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1 ;
- GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_OD ;
- GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ ;
- GPIO_Init(GPIOF, &GPIO_InitStructure) ;
- GPIO_PinRemapConfig2(PCFR6,PCFR6_REMAP_I2C2_1, ENABLE);
-
- /* Enable I2C2 */
-
-
- I2C_InitStructure.I2C_Protocol = I2C_PROTOCOL_I2C;
- I2C_InitStructure.I2C_DutyCycle = I2C_DUTYCYCLE_2;
- I2C_InitStructure.I2C_BitRate = 400000;
- I2C_InitStructure.I2C_AddressingMode = I2C_ADDRESSING_MODE_7BIT;
- I2C_InitStructure.I2C_DeviceAddress = 0X0A;
- I2C_Init(I2C2, &I2C_InitStructure);
- I2C_Enable(I2C2, ENABLE );
- I2C_Acknowledge_Enable(I2C2,ENABLE);
- }
复制代码 上面是初始化I2C2的代码,还是按照手册说明重映射那两位I2C2_REMAP[1:0]=11,即GPIO_PinRemapConfig2(PCFR6,PCFR6_REMAP_I2C2_1, ENABLE);这一句,同时要打开复用时钟。- s8 I2C2_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
- {
- dev_addr=dev_addr<<1;
- /* While the bus is busy */
- while(I2C_GetBitState( I2C2 , I2C_FLAG_I2CBSY));
- if(cnt == 2)
- {
- I2C_NACKPosition_Enable(I2C2,I2C_NACKPOSITION_NEXT);
- }
-
- /* Send START condition */
- I2C_StartOnBus_Enable( I2C2 , ENABLE );
-
- /* Test on EV5 and clear it */
- while( !I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_SBSEND ));
-
- /* Send EEPROM address for write */
- I2C_AddressingDevice_7bit( I2C2 , dev_addr, I2C_DIRECTION_TRANSMITTER );
-
- /* Test on EV6 and clear it */
- while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND));
-
- /* Wait until the transmit data buffer is empty */
- while( I2C_GetBitState( I2C2 , I2C_FLAG_TBE ) != SET );
- /* Clear EV6 by setting again the PE bit */
- I2C_Enable(I2C2, ENABLE);
-
- I2C_SendData(I2C2, reg_addr);
-
- /* Test on EV8 and clear it */
- while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED));
-
- /* Send STRAT condition a second time */
- I2C_StartOnBus_Enable( I2C2 , ENABLE );
-
- /* Test on EV5 and clear it */
- while( !I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_SBSEND ));
-
- /* Send EEPROM address for read */
- I2C_AddressingDevice_7bit(I2C2, dev_addr, I2C_DIRECTION_RECEIVER);
- if(cnt < 3)
- {
- /* Disable Acknowledgement */
- I2C_Acknowledge_Enable(I2C2, DISABLE);
- }
-
- /* Test on EV6 and clear it */
- while(!I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_RECEIVER_ADDSEND ) );
-
- if(cnt == 1)
- {
- /* Send STOP Condition */
- I2C_StopOnBus_Enable(I2C2, ENABLE);
- }
-
- /* While there is data to be read */
- while(cnt)
- {
- if(cnt == 3)
- {
- /* Wait until the BTC is set */
- while( I2C_GetBitState( I2C2 , I2C_FLAG_BTC ) != SET );
- /* Disable Acknowledgement */
- I2C_Acknowledge_Enable(I2C2, DISABLE);
-
- }
- if(cnt == 2)
- {
- /* Wait until the BTC is set */
- while( I2C_GetBitState( I2C2 , I2C_FLAG_BTC ) != SET );
- /* Send STOP Condition */
- I2C_StopOnBus_Enable(I2C2, ENABLE);
- }
-
- /* Test on EV7 and clear it */
- if(I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_RECEIVED))
- {
- /* Read a byte from the EEPROM */
- *reg_data = I2C_ReceiveData(I2C2);
-
- /* Point to the next location where the byte read will be saved */
- reg_data++;
-
- /* Decrement the read bytes counter */
- cnt--;
- }
- }
- /* Enable Acknowledgement to be ready for another reception */
- I2C_Acknowledge_Enable( I2C2 , ENABLE );
- I2C_NACKPosition_Enable(I2C2,I2C_NACKPOSITION_CURRENT);
- return 0;
- }
复制代码 上面是I2C2读数据的函数,已经封装好了,发送的设备地址是没有移位之前的7位设备地址,然后自动进行移位读取数据。- s8 I2C2_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
- {
- dev_addr=dev_addr<<1;
- /* While the bus is busy */
- while(I2C_GetBitState( I2C2 , I2C_FLAG_I2CBSY));
-
- /* Send START condition */
- I2C_StartOnBus_Enable( I2C2 , ENABLE );
-
- /* Test on EV5 and clear it */
- while(!I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_SBSEND));
-
- /* Test on EV6 and clear it */
- I2C_AddressingDevice_7bit( I2C2 , dev_addr, I2C_DIRECTION_TRANSMITTER);
-
- /* Test on EV6 and clear it */
- while(!I2C_StateDetect( I2C2 , I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND));
-
- /* Wait until the transmit data buffer is empty */
- while( I2C_GetBitState( I2C2 , I2C_FLAG_TBE ) != SET );
-
- /* Send the EEPROM's internal address to write to */
-
- I2C_SendData(I2C2, reg_addr);
-
- /* Test on EV8 and clear it */
- while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED));
-
- /* While there is data to be written */
- while(cnt--)
- {
- /* Send the current byte */
- I2C_SendData(I2C2, *reg_data);
-
- /* Point to the next byte to be written */
- reg_data++;
-
- /* Test on EV8 and clear it */
- while(!I2C_StateDetect(I2C2, I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED));
- }
-
- /* Send STOP condition */
- I2C_StopOnBus_Enable( I2C2, ENABLE );
- return 0;
- }
复制代码 而写函数和读函数类似,应该说比读数据函数更简单,不用转换读写状态。
BMP180是BOSCH公司推出的一款廉价气压计,相比于MS5611气压计价格差好几倍,各项参数也是一般,测量范围在300-1100hPa,而BOSCH公司还为该芯片提供了驱动源码,直接就放在了github上,参考其中的API,替换了自己的I2C读写函数就行了。- s8 BMP180_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
- {
- // s32 iError = BMP180_INIT_VALUE;
- // u8 array[I2C_BUFFER_LEN];
- // u8 stringpos = BMP180_INIT_VALUE;
- // array[BMP180_INIT_VALUE] = reg_addr;
- // for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
- // array[stringpos + C_BMP180_ONE_U8X] = *(reg_data + stringpos);
- // }
- /*
- * Please take the below function as your reference for
- * write the data using I2C communication
- * "IERROR = I2C_WRITE_STRING(DEV_ADDR, ARRAY, CNT+C_BMP180_ONE_U8X)"
- * add your I2C write function here
- * iError is an return value of I2C read function
- * Please select your valid return value
- * In the driver SUCCESS defined as BMP180_INIT_VALUE
- * and FAILURE defined as -C_BMP180_ONE_U8X
- * Note :
- * This is a full duplex operation,
- * The first read data is discarded, for that extra write operation
- * have to be initiated. For that cnt+C_BMP180_ONE_U8X operation done in the I2C write string function
- * For more information please refer data sheet SPI communication:
- */
- //return (s8)iError;
- return I2C2_bus_write(dev_addr,reg_addr,reg_data,cnt);
- }
复制代码- s8 BMP180_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
- {
- // s32 iError = BMP180_INIT_VALUE;
- // u8 array[I2C_BUFFER_LEN] = {BMP180_INIT_VALUE};
- // u8 stringpos = BMP180_INIT_VALUE;
- // array[BMP180_INIT_VALUE] = reg_addr;
- // /* Please take the below function as your reference
- // * for read the data using I2C communication
- // * add your I2C rad function here.
- // * "IERROR = I2C_WRITE_READ_STRING(DEV_ADDR, ARRAY, ARRAY, C_BMP180_ONE_U8X, CNT)"
- // * iError is an return value of SPI write function
- // * Please select your valid return value
- // * In the driver SUCCESS defined as BMP180_INIT_VALUE
- // * and FAILURE defined as -C_BMP180_ONE_U8X
- // */
- // for (stringpos = BMP180_INIT_VALUE; stringpos < cnt; stringpos++) {
- // *(reg_data + stringpos) = array[stringpos];
- // }
- // return (s8)iError;
- return I2C2_bus_read(dev_addr,reg_addr,reg_data,cnt);
- }
复制代码 还有替换掉延时函数,同时声明#define BMP180_API,最后移位BMP180的设备地址,然后直接调用官方给出的一个demo函数就能读取温度和气压,bmp180_data_readout_template()函数。
根据手册里给出的计算海拔的公式可以大致计算所在地的海拔,计算如下所示- /****************************************************************************
- * This API is used to read the
- * true temperature(t) value input
- * parameter as uncompensated temperature(ut)
- *
- ***************************************************************************/
- temperature= bmp180_get_temperature(v_uncomp_temp_u16)*0.1;
- /****************************************************************************
- * This API is used to read the
- * true pressure(p) value
- * input parameter as uncompensated pressure(up)
- *
- ***************************************************************************/
- pressure= bmp180_get_pressure(v_uncomp_press_u32)*1.0;
-
- Altitude=(44330.0*(1.0-pow(pressure/101325.0,1.0/5.255)));
- 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完全是反过来的(就是内外排针要和上面的丝印对调)。
|
|