非常感谢极术社区和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
文件名 | 大小 | 下载次数 | 操作 |
---|---|---|---|
T_H_Detector.zip | 583.83KB | 0 | 下载 |