- 开发环境搭建
在ICEasy的样片申请页面可以直接跳转到相关工具文档的下载页面,需要最新版本的IDE和SDK也可以到GD32官网直接下载

GD32EmbeddedBuilder是GD32官方提供的IDE,直接将下载下来的压缩包解压出来就能用
GD32AllInOneProgrammer是烧录工具,可以用串口ISP烧录固件
GD32VW55x_Firmware_Library是基础固件库,里面不包含ble和wifi相关的
GD32VW55x_RELEASE是ble和wifi固件库
其他的数据手册和应用笔记就不一一介绍了
- AHT20和OLED驱动
点灯的过程就跳过了,直接开始移植AHT20和OLED,通过OLED显示温湿度,OLED的驱动芯片是SSD1315,OLED和AHT20的驱动方法网上有很多,并且直接让AI生成都行,这里就不过多介绍了,主要介绍一下硬件I2C的实现,I2C的使用可以参考GD32VW55x_Firmware_Library中I2C的例程,针对SSD1315和AHT20实现I2C读写方法
#include "gd32vw55x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "yuyy_fonts.h"
#include "yuyy_ssd1315.h"
#include "yuyy_aht20.h"
#define I2c_TIMEOUT 0xF000
void i2c_config(void)
{
/* enable GPIOA clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* enable I2C0 clock */
rcu_periph_clock_enable(RCU_I2C0);
/* connect PA2 to I2C0_SCL */
gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_2);
/* connect PA3 to I2C0_SDA */
gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_3);
/* configure GPIO pins of I2C0 */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_2);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, GPIO_PIN_3);
/* configure I2C timing */
i2c_timing_config(I2C0, 7, 0x1, 0);
i2c_master_clock_config(I2C0, 0x31, 0x31);
i2c_enable(I2C0);
}
uint8_t i2c_writeregdatas(uint32_t i2c,uint16_t addr,uint8_t *regs,uint8_t reglen,uint8_t *datas,uint32_t datalen)
{
uint16_t timeout = 0;
uint32_t i = 0;
uint8_t ret = 0;
addr = (addr<<1)&0xFFFE;
i2c_master_addressing(i2c, addr, I2C_MASTER_TRANSMIT);
i2c_transfer_byte_number_config(i2c, reglen+datalen);
while(i2c_flag_get(i2c, I2C_FLAG_I2CBSY))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 1;
}
i2c_start_on_bus(i2c);
I2C_STAT(i2c) |= I2C_STAT_TBE;
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_TBE))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 2;
}
i = 0;
while (i < reglen)
{
timeout = 0;
i2c_data_transmit(i2c, regs[i]);
i++;
while(!i2c_flag_get(i2c, I2C_FLAG_TI))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 3;
}
}
i = 0;
while (i < datalen)
{
timeout = 0;
i2c_data_transmit(i2c, datas[i]);
i++;
while(!i2c_flag_get(i2c, I2C_FLAG_TI))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 5;
}
}
if(datalen > 0)
{
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_TC))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 6;
}
}
i2c_stop_on_bus(i2c);
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_STPDET))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 7;
}
i2c_flag_clear(i2c, I2C_FLAG_STPDET);
return 0;
}
uint8_t i2c_readregdatas(uint32_t i2c,uint16_t addr,uint8_t *regs,uint8_t reglen,uint8_t *datas,uint32_t datalen)
{
uint16_t timeout = 0;
uint32_t i = 0;
uint8_t ret = 0;
addr = (addr<<1)&0xFFFE;
if(reglen > 0)
{
i2c_master_addressing(i2c, addr, I2C_MASTER_TRANSMIT);
i2c_transfer_byte_number_config(i2c, reglen);
while(i2c_flag_get(i2c, I2C_FLAG_I2CBSY))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 1;
}
i2c_start_on_bus(i2c);
I2C_STAT(i2c) |= I2C_STAT_TBE;
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_TBE))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 2;
}
i = 0;
while (i < reglen)
{
timeout = 0;
i2c_data_transmit(i2c, regs[i]);
i++;
while(!i2c_flag_get(i2c, I2C_FLAG_TI))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 3;
}
}
while(!i2c_flag_get(i2c, I2C_FLAG_TC))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 4;
}
}
i2c_master_addressing(i2c, addr, I2C_MASTER_RECEIVE);
i2c_transfer_byte_number_config(i2c, datalen);
while(i2c_flag_get(i2c, I2C_FLAG_I2CBSY))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 5;
}
i2c_start_on_bus(i2c);
i = 0;
while (i < datalen)
{
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_RBNE))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 6;
}
datas[i] = i2c_data_receive(i2c);
i++;
}
if(datalen > 0)
{
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_TC))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 7;
}
}
i2c_stop_on_bus(i2c);
timeout = 0;
while(!i2c_flag_get(i2c, I2C_FLAG_STPDET))
{
timeout++;
if(timeout >= I2c_TIMEOUT)
return 8;
}
i2c_flag_clear(i2c, I2C_FLAG_STPDET);
return 0;
}
uint8_t oled_writeregdatas(uint32_t i2c,uint16_t addr,uint8_t reg,uint8_t *datas,uint32_t datalen)
{
return i2c_writeregdatas(i2c, addr, ®, 1, datas, datalen);
}
uint8_t aht20_writedatas(uint32_t i2c,uint16_t addr,uint8_t *datas,uint32_t datalen)
{
return i2c_writeregdatas(i2c, addr, NULL, 0, datas, datalen);
}
uint8_t aht20_readdatas(uint32_t i2c,uint16_t addr,uint8_t *datas,uint32_t datalen)
{
return i2c_readregdatas(i2c, addr, NULL, 0, datas, datalen);
}
YUYY_SSD1315_DEV_Type oled;
void oledInit()
{
YUYY_SSD1315_InitConfig_Type config;
YUYY_SSD1315_ConfigInit(&config);
config.seg_direction = YUYY_SSD1315_DIRECTIN_REVERSE;
config.com_direction = YUYY_SSD1315_DIRECTIN_REVERSE;
oled.com_type = YUYY_SSD1315_COM_I2C_SA0_0;
oled.driver.com = (uint32_t *)I2C0;;
oled.driver.i2c_senddatas_func = (YUYY_SSD1315_I2CSendDatasFunc_Type)oled_writeregdatas;
YUYY_SSD1315_Init(&oled,&config);
YUYY_SSD1315_ClearScreen(&oled);
YUYY_SSD1315_DisplayASCIIString8x16(&oled,0,0," GD32VW553",YUYY_SSD1315_DISPLAY_MODE_NOMARL,0);
YUYY_SSD1315_DisplayASCIIString8x16(&oled,2,0," I2C OLED",YUYY_SSD1315_DISPLAY_MODE_NOMARL,0);
YUYY_SSD1315_DisplayASCIIString8x16(&oled,6,0," YUYY1989",YUYY_SSD1315_DISPLAY_MODE_NOMARL,0);
}
YUYY_AHT20_DEV_Type aht20;
void aht20init(void)
{
aht20.i2cx = (uint32_t *)I2C0;
aht20.delayms_func = (YUYY_AHT20_DelayMsFunc_Type)delay_1ms;
aht20.i2c_senddatas_func = (YUYY_AHT20_I2CSendDatasFunc_Type)aht20_writedatas;
aht20.i2c_readdatas_func = (YUYY_AHT20_I2CReadDatasFunc_Type)aht20_readdatas;
YUYY_AHT20_Init(&aht20);
}
void readht(void)
{
char str[17];
int16_t tem,hum;
YUYY_AHT20_StartCalAndReadHT(&aht20,&tem,&hum);
sprintf(str,"T:%.2f H:%.2f",tem/100.0f,hum/100.0f);
YUYY_SSD1315_DisplayASCIIString8x16(&oled,4,0,str,YUYY_SSD1315_DISPLAY_MODE_NOMARL,0);
}
int main(void)
{
systick_config();
/* enable the LED clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* configure LED GPIO port */
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
/* reset LED GPIO pin */
gpio_bit_reset(GPIOB, GPIO_PIN_2);
i2c_config();
oledInit();
aht20init();
while(1) {
gpio_bit_set(GPIOB, GPIO_PIN_2);
delay_1ms(500);
gpio_bit_reset(GPIOB, GPIO_PIN_2);
delay_1ms(500);
readht();
}
}这里需要注意一下,编译器默认没有开启float类型的printf输出,需要在工程设置中勾选这个

- 固件烧录方法
手里没有GDLink,只能通过串口ISP进行烧录,开发板板载了USB转串口可以不用另外外接USB转串口工具即可进行ISP烧录,在连接PC前需要将板子上的这个开关拨到ON

如果操作不方便也可以短接PC8和VCC

之后连接PC,打开GD32AllInOneProgrammer,选择正确的串口,点击连接,选择固件,最后选择下载就行了

上面的温湿度固件烧录后显示如下图

波特率那里可以不用动,保持默认也能正常烧录成功
- 通过BLE发送温湿度到手机
先通过官方例程ble_app_uart熟悉一下BLE,路径在GD32VW55x_RELEASE_V1.0.3g\MSDK\examples\ble\peripheral\ble_app_uart
打开GD32EmbeddedBuilder导入这个工程,如何导入工程请参考GD32 Embedded Builder User Manual.pdf,直接编译,将编译生成的BLE_APP_UART.bin烧录到开发板
需要注意的是这个工程使用的串口是UART2 TX:PA6 RX:PA7,需要外接个USB转串口,连接好后在PC上的串口调试工具会输出如下信息

在手机上安装一个蓝牙的调试工具,我这里用的是nRF Connect,打开后扫描设备,出现的这个GB-BLE-DEV就是开发板,点击连接开始配对

配对成功后会出现如下的页面

点击这个箭头

选择发送文本并填入想要发送的内容

点击发送后PC上的串口调试工具会输出相应的内容

点击下面这个箭头

在PC上的串口调试工具填上文本并点击发送

在手机上也能显示相应的内容

接下来改造一下这个例程,将温湿度以1Hz的频率通过蓝牙发送到手机,打开app_uart.c,把上面已经完成的温湿度代码除main函数外都复制进去
找到app_uart_task这个函数,将里面的内容替换掉
static void app_uart_task(void *param)
{
char str[17];
uint8_t aht20_flag = 0;
int16_t tem,hum;
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
i2c_config();
oledInit();
for (;;) {
if(aht20_flag == 0)
{
vTaskDelay(50);
aht20_flag = 1;
aht20init();
}
if(aht20_flag == 1)
{
YUYY_AHT20_StartCal(&aht20);
vTaskDelay(100);
YUYY_AHT20_ReadHT(&aht20,&tem,&hum);
sprintf(str,"T:%.2f H:%.2f",tem/100.0f,hum/100.0f);
YUYY_SSD1315_DisplayASCIIString8x16(&oled,4,0,str,YUYY_SSD1315_DISPLAY_MODE_NOMARL,0);
ble_datatrans_srv_tx(conn_idx, (uint8_t *)str, strlen(str));
}
gpio_bit_set(GPIOB, GPIO_PIN_2);
vTaskDelay(400);
gpio_bit_reset(GPIOB, GPIO_PIN_2);
vTaskDelay(500);
}
}烧录后在手机端用nRFConnect连接后就能看到温湿度了

当然这只是个简单的演示,真正想做产品的话可以开发个APP或小程序更美观的展示,通讯也不要直接用文本传输比较浪费带宽

开源社区 


