萤火工场GD32VW553-IOT-V2实现温湿度显示

分享作者:yuyy
作者昵称:流浪剑士
评测品牌:萤火工场
评测型号:GD32VW553-IOT-V2
发布时间:2026-07-29 09:49:15
1
概要
以前用的都是Arm内核的MCU,还没接触过RISC-V,看到ICEasy在进行GD32VW553样品申请活动,这是个带ble和wifi的RISC-V芯片,就想申请来试试,通过I2C读取AHT20的温湿度并在OLED上显示,用蓝牙连接手机后可以在手机上接收温湿度信息
开源口碑分享内容
  • 开发环境搭建

在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或小程序更美观的展示,通讯也不要直接用文本传输比较浪费带宽

全部评论
暂无评论
0/144