本帖最后由 zealsoft 于 2023-7-5 22:33 编辑

感谢面包板社区和中国移动所提供的中国移动万耦天工物联网开发板评测。上次介绍万耦天工STM32F103开发板的开发环境的构建,今天运用ADC读取该处理板自带的光敏传感器并在LCD上显示。

1. 利用STM32 CubeMX进行ADC配置

精英 STM32F103 板载了一个光敏二极管(光敏电阻),作为光敏传感器,它对光的变化非常敏感。我们利用 ADC3 的通道 6(PF8)来读取光敏二极管电压的变化,从而得到环境光线的变化,并将得到的光线强度,显示在 LCD 上面。

在C:\OneOS-V3.0.1\projects\stm32f103zet6-atk-elite\board\CubeMX_Config目录下有个CubeMX_Config.ioc文件,这个文件就是开发板的配置文件,双击该文件就可以使用CubeMX打开,如下图所示。

forum.jpg

点击窗口左侧的Analog,在其中选择ADC3,确保ADC3的IN6被选中。下方参数窗口中的参数基本不用修改,只有一个参数要调整一下,点击Rank → Sampling Time,将其修改为239.5 Cycles。

forum.jpg

参数配置后,点击右上角的“Generate Code”按钮,CubeMX就会自动生成板子的初始化代码。OneOS Cube在编译工程代码时并不直接使用CubeMX生成的代码,而是将其转换为C:\OneOS-V3.0.1\projects\stm32f103zet6-atk-elite\board\CubeMX_Config\Src\bsp.c,然后编译bsp.c。

使用CubeMX后,我们就无需手工在程序里面初始化设备参数了。

2. ADC编程读取光敏传感器的数值

OneOS提供了以下和ADC设备相关的API函数。

函数

说明

os_device_find()

根据ADC设备名称寻找设备并获取设备指针

os_device_open()

打开设备

os_device_control()

控制ADC设备

os_device_read()

读取ADC设备数据(电压值:mV)

os_device_close()

关闭设备


OneOS的stm32f103zet6-atk-elite模板默认是使能ADC1和ADC3设备的,所以我们就无需使用menuconfig激活ADC设备了。

我在start_adc函数中进行了ADC3设备的初始化和使能操作,并建立了一个定时器周期读取ADC3的数据。

static os_err_t start_adc(int argc, char **argv)
  • {
  •     os_timer_id TIMER_PERIODIC = OS_NULL;
  •    
  •     adc_dev = os_device_find("adc3");
  •     OS_ASSERT_EX(OS_NULL != adc_dev, "adc device not find! \r\n");
  •    
  •     os_device_open(adc_dev);
  •    
  •     if (OS_SUCCESS != os_device_control(adc_dev, OS_ADC_CMD_ENABLE, OS_NULL))
  •     {
  •         os_kprintf("adc device cannot enable! \r\n");
  •         os_device_close(adc_dev);
  •         return 1;
  •     }
  •    
  •     timer_periodic_timeout(OS_NULL);
  •    
  •     TIMER_PERIODIC = os_timer_create(OS_NULL, "timer", timer_periodic_timeout, OS_NULL, 200, OS_TIMER_FLAG_PERIODIC);
  •     OS_ASSERT_EX(OS_NULL != TIMER_PERIODIC, "timer create err\r\n");
  •    
  •     os_timer_start(TIMER_PERIODIC);
  •     return 0;   
  • }
  • 复制代码




    定时器处理函数和读取ADC3数值的代码如下:

    os_device_t *adc_dev;
  • uint32_t Get_Adc(uint32_t ch)
  • {
  •     uint32_t read_buf;
  •    
  •     /* 读取设备 */
  •     os_device_read_nonblock(adc_dev, ch, &read_buf, sizeof(read_buf));
  •     os_kprintf("Voltage: %dmv\r\n", read_buf);
  •     return read_buf;
  • }
  • /**
  • * @brief 得到光照值
  • *
  • * @retval 光照值(0-100之间,0为最暗,100为最亮)
  • */
  • uint16_t Get_Light_Value(void)
  • {
  •         uint32_t adcx;
  •         adcx = Get_Adc(ADC_CHANNEL_6);             //读取光敏传感器通道
  •     if(adcx > 4000) adcx = 4000;
  •         return (uint16_t)(100 - (adcx / 40));
  • }
  • static char buffer[50] = "Hello!";
  • /**
  • * @brief       软件定时器回调函数
  • * @param       parameter : 传入参数(未用到)
  • * @retval      无
  • */
  • static void timer_periodic_timeout(void *parameter)
  • {
  •     uint16_t light;
  •    
  •     light = Get_Light_Value();        //得到光照值
  •     os_kprintf("Light: %d\r\n", light);
  •     uint8_t r, i;
  •     for(i = 0; i < 3; i++)
  •     {
  •         r = light % 10;
  •         buffer[2 - i] = '0' + r;
  •         light /= 10;
  •     }
  •     if(buffer[0] == '0')
  •     {
  •         buffer[0] = ' ';
  •         if(buffer[1] == '0')
  •             buffer[1] = ' ';
  •     }
  •     buffer[3] = 0;
  •     lcd_draw_solid_rect(30 + 7 * 12, 170, 200, 24, OS_COLOR_BLACK);
  •     lcd_show_string(30 + 7 * 12, 170, 200, 24, 24, buffer, OS_COLOR_RED);   
  • }
  • 复制代码

    3. LCD显示

    万耦天工的板子有一个TFTLCD屏幕,这个方便进行数据显示。OneOS提供了LVGL图形库的移植方案,不过我要显示的数据非常简单,就不使用LVGL图形库了,而直接使用Graphic设备来实现。Graphic设备默认是激活的,但是需要修改几个参数。在OneOS Cube的命令行输入menuconfig命令,在配置界面中选择Drivers→Graphic。需要修改其高度为320。同时,需要使能Enable draw functions。

    forum.jpg

    为了方便使用,我将用到的几个功能用函数封装了一下:

    #include <os_assert.h>
  • #include "lcd.h"
  • #include "font_asc2_1608.h"
  • #include "font_asc2_2412.h"
  • #include "font_asc2_3216.h"
  • static os_device_t      *disp_dev = 0;
  • static os_graphic_info_t info;
  • /* 初始化LCD */
  • int lcd_init(void)
  • {
  •     os_err_t          ret;
  •     disp_dev = os_device_find("lcd");
  •     OS_ASSERT(disp_dev);
  •     os_device_open(disp_dev);
  •     os_device_control(disp_dev, OS_GRAPHIC_CTRL_GET_INFO, (void *)(&info));
  •     // Add font
  •     ret = os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_ADD_FONT, (void *)&font_asc2_1608);
  •     if (ret != OS_SUCCESS)
  •         os_kprintf("add asc2_1608 error\r\n");
  •     ret = os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_ADD_FONT, (void *)&font_asc2_2412);
  •     if (ret != OS_SUCCESS)
  •         os_kprintf("add asc2_2412 error\r\n");
  •     ret = os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_ADD_FONT, (void *)&font_asc2_3216);
  •     if (ret != OS_SUCCESS)
  •         os_kprintf("add asc2_3216 error\r\n");
  • }
  • /* LCD清屏 */
  • void lcd_clear(os_color_t color)
  • {
  •     os_graphic_area_t area;
  •     os_graphic_t     *graphic = (os_graphic_t *)disp_dev;
  •     char             *fb;
  •     area.x      = 0;
  •     area.y      = 0;
  •     area.w      = graphic->info.width;
  •     area.h      = graphic->info.height;
  •     area.color  = color;
  •     area.buffer = OS_NULL;
  •     if (graphic->info.framebuffer_num > 0)
  •     {
  •         os_device_control(disp_dev, OS_GRAPHIC_CTRL_FRAME_NEXT, (void *)(&fb));
  •         os_device_control(disp_dev, OS_GRAPHIC_CTRL_FRAME_SET, (void *)(fb));
  •         os_device_control(disp_dev, OS_GRAPHIC_CTRL_FRAME_FILL, (void *)(&area));
  •         os_device_control(disp_dev, OS_GRAPHIC_CTRL_FRAME_FLUSH, (void *)0);
  •     }
  •     else
  •     {
  •         os_device_control(disp_dev, OS_GRAPHIC_CTRL_DISP_AREA, (void *)(&area));
  •     }
  • }
  • void lcd_draw_solid_rect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, os_color_t color)
  • {
  •     os_graphic_rect_t rectangle;
  •     // Draw solid rect
  •     rectangle.x     = x;
  •     rectangle.y     = y;
  •     rectangle.w     = width;
  •     rectangle.h     = height;
  •     rectangle.color = color;
  •     os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_SOLID_RECT, (void *)(&rectangle));
  • }
  • void lcd_show_string(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p, os_color_t color)
  • {
  •     os_err_t          ret;
  •     // Draw text
  •     os_graphic_pos_t txt_pos;
  •     txt_pos.x = x;
  •     txt_pos.y = y;
  •     os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_SET_TXT_CURSOR, (void *)&txt_pos);
  •     os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_SET_TXT_COLOR, (void *)&color);
  •     switch (size)
  •     {
  •     case 16:
  •         ret = os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_SET_FONT, (void *)"asc2_1608");
  •         if (ret != OS_SUCCESS)
  •             os_kprintf("set asc2_1608 error\r\n");
  •         break;
  •    
  •     case 24:
  •         ret = os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_SET_FONT, (void *)"asc2_2412");
  •         if (ret != OS_SUCCESS)
  •             os_kprintf("set asc2_2412 error\r\n");
  •         break;
  •     case 32:
  •         ret = os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_SET_FONT, (void *)"asc2_3216");
  •         if (ret != OS_SUCCESS)
  •             os_kprintf("set asc2_3216 error\r\n");
  •         break;
  •     default:
  •         os_kprintf("size error!\r\n");
  •         break;
  •     }
  •     os_device_control(disp_dev, OS_GRAPHIC_CTRL_DRAW_STRING, (void *)p);
  • }
  • 复制代码

    这样我们就可以实现数据的实时显示了,效果如下图。

    forum.jpg


    万耦天工的板子不支持网络,我专门买了一个ESP8266的模块,今天模块终于到货了,下次介绍如何利用开发板访问OneNET云,并将传感器的值发布出去。