玩转RT-Thread系列教程(8)–ADC—光敏数据的采集
一、查看电路原理图
二、添加ADC—DMA配置
1.配置Cubemx
为ADC设置频率,72/6=12分频
生成代码
2.添加Kconfig中ADC配置
3.打开env,配置ADC3
menuconfig
4.保存配置,生成mdk工程
三、ADC外设的使用
1.添加adc外设初始化
打开stm32f1xx_hal_msp.c我们可以看见,cubemx生成的代码自动添加到了该文件中。
接下来我们打开main.c复制一下初始化部分。
/**
* @brief ADC3 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC3_Init(void)
{
/* USER CODE BEGIN ADC3_Init 0 */
/* USER CODE END ADC3_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC3_Init 1 */
/* USER CODE END ADC3_Init 1 */
/** Common config
*/
hadc3.Instance = ADC3;
hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc3.Init.ContinuousConvMode = ENABLE;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc3) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC3_Init 2 */
/* USER CODE END ADC3_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
}
2.编写业务逻辑,获取光敏传感器数值
因为开发板IO引脚的电压最高为3.3v,同时ADC采用16字节对齐,所以最大数值为4096,经过换算得出换算电压公式:
V(adc) = ADC * 3.3 / 4096
完整代码:
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "button_app.h"
ADC_HandleTypeDef hadc3;
DMA_HandleTypeDef hdma_adc3;
//定义key 控制块
struct key_state_type key0 = { 0 };
struct key_state_type key1 = { 0 };
static void MX_ADC3_Init(void);
static void MX_DMA_Init(void);
static void Get_Light_Value(void);
static uint16_t adc_data;
static uint32_t light_value;
int main(void)
{
MX_DMA_Init();
MX_ADC3_Init();
HAL_ADC_Start(&hadc3);
HAL_ADC_Start_DMA(&hadc3,(uint32_t*)&adc_data,(uint32_t)1);
while (1)
{
Get_Light_Value();
rt_pin_write(LED0_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED0_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
void Get_Light_Value(void)
{
light_value = adc_data * 330/4096;
rt_kprintf("light value is:%d.%02d\r\n",light_value/100,light_value%100);
}
/**
* @brief ADC3 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC3_Init(void)
{
/* USER CODE BEGIN ADC3_Init 0 */
/* USER CODE END ADC3_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC3_Init 1 */
/* USER CODE END ADC3_Init 1 */
/** Common config
*/
hadc3.Instance = ADC3;
hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc3.Init.ContinuousConvMode = ENABLE;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc3) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC3_Init 2 */
/* USER CODE END ADC3_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
}
3.编译、下载、验证
可以看见当用手去靠近光敏传感器时,电压明显增加。
四、结合LVGL使用
上次我们学习了LVGL的移植,那么我们今天就将其应用起来做一个综合案例吧
4.1.案例分析
使用LVGL创建仪表盘,通过仪表盘来动态显示我们采集到的ADC数据。
4.2.编码实现
4.2.1创建LVGL线程
static int _lv_init = 0;
static void lvgl_tick_run(void *p)
{
if (_lv_init)
{
//LVGL心跳
lv_tick_inc(1);
}
}
static int lvgl_tick_handler_init(void)
{
rt_timer_t timer = RT_NULL;
int ret;
timer = rt_timer_create("lv_tick", lvgl_tick_run, RT_NULL, 1, RT_TIMER_FLAG_PERIODIC);
if (timer == RT_NULL)
{
return RT_ERROR;
}
ret = rt_timer_start(timer);
return ret;
}
static void lvgl_th_run(void *p)
{
tp_dev.init(); //触摸屏初始化
//
lv_init(); //lvgl系统初始化
lv_port_disp_init(); //lvgl显示接口初始化
lv_port_indev_init(); //lvgl输入接口初始化
_lv_init = 1; //开启心跳
lvgl_tick_handler_init(); //心跳定时器
//
lv_test_theme_1(lv_theme_night_init(210,NULL));
while(1)
{
tp_dev.scan(0);
lv_task_handler();
rt_thread_mdelay(5);
}
}
int rt_lvgl_init(void)
{
rt_err_t ret = RT_EOK;
rt_thread_t thread = RT_NULL;
thread = rt_thread_create("lvgl", lvgl_th_run, RT_NULL, 2048, 15, 10);
if(thread == RT_NULL)
{
return RT_ERROR;
}
rt_thread_startup(thread);
return RT_EOK;
}
INIT_APP_EXPORT(rt_lvgl_init);
4.2.2编写UI显示
/*********************
* INCLUDES
*********************/
#include "lv_test_theme_1.h"
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <stdio.h>
#if LV_USE_TESTS
/*********************
* DEFINES
*********************/
/* defined the LED0 pin: PB5 */
#define LED0_PIN GET_PIN(B, 5)
/* defined the LED1 pin: PE5 */
#define LED1_PIN GET_PIN(E, 5)
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void create_tab1(lv_obj_t * parent);
static void create_tab2(lv_obj_t * parent);
static void create_tab3(lv_obj_t * parent);
/**********************
* STATIC VARIABLES
**********************/
lv_style_t gauge_style;
lv_obj_t * gauge1;
lv_obj_t * label1;
//结构体赋值
lv_color_t needle_colors1[1];//指针的颜色
extern float light_value;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create a test screen with a lot objects and apply the given theme on them
* @param th pointer to a theme
*/
void lv_test_theme_1(lv_theme_t * th)
{
lv_theme_set_current(th);
th = lv_theme_get_current();
lv_obj_t * scr = lv_cont_create(NULL, NULL);
lv_disp_load_scr(scr);
lv_obj_t * tv = lv_tabview_create(scr, NULL);
lv_obj_set_size(tv, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_t * tab1 = lv_tabview_add_tab(tv, "RB_Team");
lv_gauge_test_start(tab1);
}
//任务回调函数
void task_cb(lv_task_t * task)
{
//设置指针的数值
lv_gauge_set_value(gauge1, 0, (rt_int16_t)light_value * 10);
}
void lv_gauge_test_start(lv_obj_t * parent)
{
//1.创建自定义样式
lv_style_copy(&gauge_style, &lv_style_pretty_color);
gauge_style.body.main_color = LV_COLOR_MAKE(0x5F, 0xB8, 0x78); //关键数值点之前的刻度线的起始颜色,为浅绿色
gauge_style.body.grad_color = LV_COLOR_MAKE(0xFF, 0xB8, 0x00); //关键数值点之前的刻度线的终止颜色,为浅黄色
gauge_style.body.padding.left = 13;//每一条刻度线的长度
gauge_style.body.padding.inner = 8;//数值标签与刻度线之间的距离
gauge_style.body.border.color = LV_COLOR_MAKE(0x33, 0x33, 0x33); //中心圆点的颜色
gauge_style.line.width = 4;//刻度线的宽度
gauge_style.text.color = LV_COLOR_WHITE;//数值标签的文本颜色
gauge_style.line.color = LV_COLOR_OLIVE;//关键数值点之后的刻度线的颜色
//仪表盘
gauge1 = lv_gauge_create(parent, NULL);//创建仪表盘
lv_obj_set_size(gauge1, 300, 300); //设置仪表盘的大小
lv_gauge_set_style(gauge1, LV_GAUGE_STYLE_MAIN, &gauge_style); //设置样式
lv_gauge_set_range(gauge1, 0, 50); //设置仪表盘的范围
needle_colors1[0] = LV_COLOR_TEAL;
lv_gauge_set_needle_count(gauge1, 1, needle_colors1); //设置指针的数量和其颜色
lv_gauge_set_value(gauge1, 0, (rt_int16_t)light_value * 10); //设置指针1指向的数值
lv_gauge_set_critical_value(gauge1, 40); //设置关键数值点
lv_gauge_set_scale(gauge1, 240, 41, 10); //设置角度,刻度线的数量,数值标签的数量
lv_obj_align(gauge1, NULL, LV_ALIGN_IN_LEFT_MID, 50, 0); //设置与屏幕居中对齐
//3.创建一个标签来显示指针1的数值
label1 = lv_label_create(parent, NULL);
lv_label_set_long_mode(label1, LV_LABEL_LONG_BREAK); //设置长文本模式
lv_obj_set_width(label1, 80); //设置固定的宽度
lv_label_set_align(label1, LV_LABEL_ALIGN_CENTER); //设置文本居中对齐
lv_label_set_style(label1, LV_LABEL_STYLE_MAIN, &lv_style_pretty); //设置样式
lv_label_set_body_draw(label1, true); //使能背景重绘制
lv_obj_align(label1, gauge1, LV_ALIGN_CENTER, 0, 60); //设置与gauge1的对齐方式
lv_label_set_text(label1, "0.0 V/h"); //设置文本
lv_label_set_recolor(label1, true); //使能文本重绘色
//4.创建一个任务来模拟速度指针的变化
lv_task_create(task_cb, 300, LV_TASK_PRIO_MID, NULL);
}
#endif /*LV_USE_TESTS*/