赞
踩
本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:cain
非常感谢极术社区和GigaDevice不定期的举行这种开发板试用的活动,使我们这种小白有机会进行学习,利用开发板做一些小的玩意,提高学习的兴趣。也感谢极术小姐姐,能够给我机会领取到开发板,而且物流邮寄的速度也很快。下面开始我们的兴趣之旅。
我拿到的开发板主控使用的是GD32F427RKT6,LQFP64封装,32位Arm® Cortex®-M4,最高可达200MHz工作频率。6组UART口,3组I2C口,51组GPIO口,当然是可以功能复用的。开发板图片如下:
拿到开发板后,计划用来做一个环境温湿度检测器,环境温湿度通过1.3”OLED显示出来。温湿度sensor采用AM2311,屏采用I2C接口的1.3”OLED屏模组。AM2311是采用单总线接口,接口简单,就三条线:电源/地/数据线。如下图所示:
单总线接口协议如下。
1.3”OLED屏驱动芯片是SH1106,I2C接口。
1、 建立工程文件
首先建立新的工程文件,导入GD32F427R的支持包,如下图所示,这部分都大同小异,度娘上很多介绍的,这里不做赘述。
2、 硬件映射
硬件映射的目的是按目前的硬件连接建立.h文件,如下图所示:
屏显示采用的是I2C1接口,PB10/PB11连接到I2C\\\_SCL和I2C\\\_SDA,温湿度总线连接到PC9。
3、 代码描述
①首先移植UART3接口及printf函数重定向,测试一下项目的建立正确与否。
#include <bsp_Uart3.h> /** 配置调试串口(UART3) **/ void bsp_UART3_config(void) { rcu_periph_clock_enable(RCU_GPIO_UART3); gpio_mode_set(DB_UART3_PORT,GPIO_MODE_AF,GPIO_PUPD_PULLUP,DB_UART3_TX_PIN|DB_UART3_RX_PIN); gpio_output_options_set(DB_UART3_PORT,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,DB_UART3_TX_PIN|DB_UART3_RX_PIN); gpio_af_set(DB_UART3_PORT,GPIO_AF_8,DB_UART3_TX_PIN|DB_UART3_RX_PIN); // usart_deinit(UART3); rcu_periph_clock_enable(RCU_DB_UART3); usart_baudrate_set(UART3,115200); usart_parity_config(UART3,USART_PM_NONE); usart_word_length_set(UART3,USART_WL_8BIT); usart_stop_bit_set(UART3,USART_STB_1BIT); usart_enable(UART3); usart_transmit_config(UART3,USART_TRANSMIT_ENABLE); usart_receive_config(UART3,USART_RECEIVE_ENABLE); } /** 重定向打印输入输出口 **/ int fputc(int ch,FILE *f) { usart_data_transmit(UART3,(uint8_t) ch); while(usart_flag_get(UART3,USART_FLAG_TC) == 0); return (ch); } int fgetc(FILE *f) { while(usart_flag_get(UART3,USART_FLAG_RBNE) == 0); return((int)(usart_data_receive(UART3))); }
②I2C1接口初始化。
#include "bsp_i2c1.h" /** I2C1初始化 **/ void bsp_I2C1_config(void) { rcu_periph_clock_enable(RCU_I2C1_PORT); rcu_periph_clock_enable(RCU_I2C1); gpio_mode_set(I2C1_PORT,GPIO_MODE_AF,GPIO_PUPD_PULLUP,I2C1_SCL_PIN|I2C1_SDA_PIN); gpio_output_options_set(I2C1_PORT,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,I2C1_SCL_PIN|I2C1_SDA_PIN); gpio_af_set(I2C1_PORT,GPIO_AF_4,I2C1_SCL_PIN|I2C1_SDA_PIN); i2c_clock_config(I2C1,I2C_Speed,I2C_DTCY_2); i2c_mode_addr_config(I2C1,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,0x0A); i2c_ack_config(I2C1,I2C_ACK_ENABLE); // i2c_ackpos_config(I2C1,I2C_ACKPOS_CURRENT); i2c_enable(I2C1); }
③OLED屏的初始化。
//初始化SH1106 void OLEDConfiguration(void) { OLED_WR_Byte(0xAE, OLED_CMD);//--display off OLED_WR_Byte(0x02, OLED_CMD);//---set low column address OLED_WR_Byte(0x10, OLED_CMD);//---set high column address OLED_WR_Byte(0x40, OLED_CMD);//--set start line address OLED_WR_Byte(0xB0, OLED_CMD);//--set page address OLED_WR_Byte(0x81, OLED_CMD); // contract control OLED_WR_Byte(0xCF, OLED_CMD);//--128 OLED_WR_Byte(0xA1, OLED_CMD);//set segment remap OLED_WR_Byte(0xA6, OLED_CMD);//--normal / reverse OLED_WR_Byte(0xA8, OLED_CMD);//--set multiplex ratio(1 to 64) OLED_WR_Byte(0x3F, OLED_CMD);//--1/64 duty OLED_WR_Byte(0xAD, OLED_CMD);//set charge pump enable OLED_WR_Byte(0x8B, OLED_CMD);//-0x8B 内供 VCC OLED_WR_Byte(0x33, OLED_CMD);//-0X30---0X33 set VPP 9V OLED_WR_Byte(0xC8, OLED_CMD);//Com scan direction OLED_WR_Byte(0xD3, OLED_CMD);//-set display offset OLED_WR_Byte(0x00, OLED_CMD);// OLED_WR_Byte(0xD5, OLED_CMD);//set osc division OLED_WR_Byte(0x80, OLED_CMD);// OLED_WR_Byte(0xD9, OLED_CMD);//set area color mode off OLED_WR_Byte(0x05, OLED_CMD);// OLED_WR_Byte(0xD9, OLED_CMD);//Set Pre-Charge Period OLED_WR_Byte(0x1F, OLED_CMD);// OLED_WR_Byte(0xDA, OLED_CMD);//set com pin configuartion OLED_WR_Byte(0x12, OLED_CMD);// OLED_WR_Byte(0xDB, OLED_CMD);//set Vcomh OLED_WR_Byte(0x40, OLED_CMD);// OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel OLED_Display_Status(Display_Clear); OLED_Set_Pos(0, 0); }
④建立字符串及数字显示函数,以方便后续温湿度的显示。
//在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 16/12 void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr) { uint8_t c = 0, i = 0; c = chr - ' ';//得到偏移后的值 if(x > Max_Column - 1) { x = 0; y += 2; } if(SIZE == 16) { OLED_Set_Pos(x, y); for(i = 0; i < 8; i ++) { OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA); } OLED_Set_Pos(x, y + 1); for(i = 0; i < 8; i ++) { OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA); } } else { OLED_Set_Pos(x, y + 1); for(i = 0; i < 6; i ++) { OLED_WR_Byte(F6x8[c][i],OLED_DATA); } } } //m^n函数 uint32_t oled_pow(uint8_t m,uint8_t n) { uint32_t result = 1; while(n --) { result *= m; } return result; } //显示2个数字 //x,y :起点坐标 //len :数字的位数 //size:字体大小 //mode:模式 0,填充模式;1,叠加模式 //num:数值(0~4294967295); void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size) { uint8_t t,temp; uint8_t enshow = 0; for(t = 0; t < len; t ++) { temp = (num / oled_pow(10, len - t - 1)) % 10; if(enshow == 0 && t < (len - 1)) { if(temp == 0) { OLED_ShowChar(x + (size / 2) * t, y, ' '); continue; }else enshow = 1; } OLED_ShowChar(x + (size / 2) * t, y, temp + '0'); } } //显示一个字符号串 void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr) { uint8_t j = 0; while (chr[j] != '\0') { OLED_ShowChar(x, y, chr[j]); x += 8; if(x > 120) { x = 0; y += 2; } j++; } } 显示汉字 void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no) { uint8_t t, adder = 0; OLED_Set_Pos(x, y); for(t = 0; t < 16; t ++) { OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA); adder += 1; } OLED_Set_Pos(x, y + 1); for(t = 0; t < 16; t ++) { OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA); adder += 1; } }
⑤AM2311初始化,建立协议接口。
void am2311_in_init(void) //IO设置为输入 { rcu_periph_clock_enable(RCU_TandH_port); gpio_mode_set(TandH_port,GPIO_MODE_INPUT,GPIO_PUPD_NONE,TandH_pin); gpio_output_options_set(TandH_port,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,TandH_pin); } void am2311_out_init(void) //IO设置为输出 { rcu_periph_clock_enable(RCU_TandH_port); gpio_mode_set(TandH_port,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,TandH_pin); gpio_output_options_set(TandH_port,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,TandH_pin); } void am2311_reset(void) //向AM2311发送读取信号,拉低至少1ms { am2311_out_init(); AM2311_OUT(0); delay_1ms(2); //拉低2ms AM2311_OUT(1); am2311_in_init(); //设置为输入,释放总线 delay_10us(2); //20us后AM2311响应 }
⑥读取温湿度函数。
uint16_t am2311_read_data(int16_t *cache) { uint16_t timeout = 0; uint8_t i,data_buf[5]; uint8_t check_data = 0; am2311_reset(); if(AM2311_CHECK == 0) //接收到响应信号 = 80us的低电平 + 80us的高电平 { while(AM2311_CHECK == 0) //80us的低电平信号是否完毕 { timeout++; if(timeout > 1000) //防止进入死循环 return 0; } timeout = 0; while(AM2311_CHECK == 1) //80us高电平信号是否完毕 { timeout++; if(timeout > 1000) //防止进入死循环 return 0; } for(i = 0; i < 5; i++) { data_buf[i] = am2311_read_byte(); } check_data = data_buf[0]+data_buf[1]+data_buf[2]+data_buf[3]; if(check_data == data_buf[4])//数据校验 { printf("SENSOR Read successful! \r\n"); cache[0] = data_buf[0]*256 + data_buf[1]; if(data_buf[2] & 0x80) //零下 { cache[1] = (data_buf[2]&0x7F)*256 + data_buf[3]; cache[1] = 0 - cache[1]; } else //零上 { cache[1] = data_buf[2]*256 + data_buf[3]; } return 1; } } printf("SENSOR Read Failure! \r\n"); return 0; }
⑦main主函数中将温湿度读取函数及屏显示函数连接起来,以实现设计意图。
int main(void) { int16_t humi=0,temp=0; int16_t buffer[2]; systick_config(); bsp_UART3_config(); bsp_I2C1_config(); OLEDConfiguration(); OLED_ShowString(0,3,"GD32F427R study"); delay_1ms(1500); delay_1ms(1500); OLED_Display_Status(Display_Clear); OLED_Display_Status(Display_ON); OLED_ShowCHinese(0,1,0); //温 OLED_ShowCHinese(16,1,2); //度 OLED_ShowCHinese(32,1,3); //: OLED_ShowCHinese(0,3,1); //湿 OLED_ShowCHinese(16,3,2); //度 OLED_ShowCHinese(32,3,3); //: OLED_ShowString(0,6,"Design by cain"); printf("system start ... \r\n"); while(1) { am2311_read_data(buffer); //连续两次采集时间间隔要大于2S humi = buffer[0]/10; temp = buffer[1]/10; OLED_ShowNum(48,1,temp,2,16); OLED_ShowNum(48,3,humi,2,16); delay_1ms(500); //AM2311上电后要等待2S以越过不稳定状态 delay_1ms(500); delay_1ms(500); delay_1ms(500); delay_1ms(500); printf("Humidity = %d Temperature = %d \r\n",humi, temp); } }
4、 编译下载
Build 项目文件:
编译没有错误,下载到开发板中,显示效果如下:
5、 试用总结
通过本次试用,深切的感觉到GD32F427RKT6功能相当强大,适用于多种场合,外设资源丰富,速度能满足大部分消费类电子的要求,应用前景广阔。
视频显示结果
对本项目有兴趣的伙伴可以通过百度网盘下载相关源码:
链接:https://pan.baidu.com/s/19YNXC-xAAfHfApy5m1VO9w?pwd=9miy
提取码:9miy
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。