wo4fisher 发表于 2022-4-4 22:50

[平头哥RVB2601创意应用开发]体验分享四:ADC 多通道测试+LVGL显示

# 欢迎使用Markdown编辑器

## 合集

###1. [平头哥RVB2601创意应用开发]体验分享一:开箱、环境搭建、输出helloworld](https://bbs.eeworld.com.cn/thread-1197148-1-1.html)

###2. [平头哥RVB2601创意应用开发]体验分享二:多种方式点灯,组件学习](https://bbs.eeworld.com.cn/thread-1197151-1-1.html)

###3. [[平头哥RVB2601创意应用开发]体验分享三:基于RTOS实现按键控制LED](https://bbs.eeworld.com.cn/thread-1197189-1-1.html)

## 一、 ADC的使用

### 1.1 硬件分析
主要使用2601的ADC采集joystick的x和y方向AD值。
通过芯片和电路分析,这里使用PA5(PA5_ADC_A3)和PA6(PA6_ADC_A4),分别是2601的ADC_CH2和ADC_CH3.
如下图所示,断开原来J1(11-12)和J2(5-6)的短接帽,然后将J1-11和J2_6分别连接joystick的x、y信号输出。



### 1.2 ADC初始化
这里使用CSI2接口。(https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/CSI%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%8E%A5%E5%8F%A3/CSI2/ADC.html)
这里主要使用以下函数:
函数        说明
csi_adc_init        ADC设备初始化
csi_adc_start        启动ADC数据转换(同步)
csi_adc_channel_enable        开启或者关闭一个ADC通道
csi_adc_channel_sampling_time        设置通道采样时间
csi_adc_sampling_time        设置ADC采样时间
csi_adc_freq_div        设置ADC分频系数
主要代码如下:

```
void myAdc_init(void)
{

    int ret;
    /* GPIO init */
    csi_pin_set_mux(EXAMPLE_ADC_CHANNEL3_PIN, EXAMPLE_ADC_CHANNEL3_PIN_FUNC); //通道3引脚复用
    csi_pin_set_mux(EXAMPLE_ADC_CHANNEL2_PIN, EXAMPLE_ADC_CHANNEL2_PIN_FUNC); //通道2引脚复用

    /* Initialize ADC peripheral */
    ret = csi_adc_init(&adc, 0); // 0为idx默认值。
    if (ret != CSI_OK)
      LOGD(TAG, "adc init error .\n");

    /* Configure frequency divsion, this value can be one of(4 8 16 32 64 128) */
    ret = csi_adc_freq_div(&adc, 128);
    if (ret != CSI_OK)
      LOGD(TAG, "adc_freq_div = %d .\n", ret);

    /* Configure sampling time */
    ret = csi_adc_sampling_time(&adc, 5);
    if (ret != CSI_OK)
      LOGD(TAG, "adc_sampling_time error .\n");

    ret = csi_adc_channel_enable(&adc, EXAMPLE_ADC_CHANNEL3, true); //使能通道3
    if (ret != CSI_OK)
      LOGD(TAG, "channel3_enable error .\n");
    ret = csi_adc_channel_enable(&adc, EXAMPLE_ADC_CHANNEL2, true); //使能通道2
    if (ret != CSI_OK)
      LOGD(TAG, "channel2_enable error .\n");
}
```
### 1.3 读取转换结果

csi_adc_read        读取ADC转换结果

主要代码如下:

```
// 一次转换一个通道,按顺序依次从使能的通道,按照通道号由小到大逐个通道转换。
// 这里调用myAdc_get()函数两次,即可以转换通道2和通道3.
uint32_t myAdc_get(void)
{
    int32_t ret;
    /* Trigger new conversion */
    ret = csi_adc_start(&adc);
    if (ret != CSI_OK)
      LOGD(TAG, "adc_start error .\n");

    /* Read result */
    ret = csi_adc_read(&adc);

    return ret;
}
```

### 1.4 主函数中任务设计

```
static void application_adcTask_entry(void *arg)
{
    uint32_t res_x = 0,res_y =0; //保存转换结果
    myAdc_init();//adc初始化

    while (1)
    {
      res_x = myAdc_get(); //获取通道2 结果
                res_y = myAdc_get(); //获取通道3结果;这里顺序是按照使能的通道,按照通道号由小到大逐次转换,因为使能了2个通道,所以调用两次
      LOGD(TAG, "adc = %d,%d\n", res_x,res_y);//串口打印转换结果
                //互斥量上锁,将结果传送到adcRes[]供lvgl任务调用
      if (1 == aos_mutex_is_valid(&adc_mutex))
      {
            aos_mutex_lock(&adc_mutex, AOS_WAIT_FOREVER);
            adcRes = res_x;
            adcRes = res_y;
            aos_mutex_unlock(&adc_mutex);
      }
      aos_msleep(1000);
    }
    aos_task_exit(0);
}
```


## 二、 使用lvgl label显示AD转换值

### 2.1 oled驱动和lvgl gui库的移植

这里使用ch2601_gui_demo中的文件,oeld.c和oled.h。



###2.2 lvgl任务设计

界面如下:



全局变量定义:
---
```
lv_obj_t *lbl_adc_x = NULL;
lv_obj_t *lbl_adc_y = NULL;
```
创建label子函数:
---
```
static void gui_label_create(void)
{
    lv_obj_t *lbl_title = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_long_mode(lbl_title, LV_LABEL_LONG_BREAK);
    lv_label_set_align(lbl_title, LV_LABEL_ALIGN_CENTER);
    lv_obj_set_pos(lbl_title, 0, 2);
    lv_obj_set_size(lbl_title, 128, 20);
    lv_label_set_text(lbl_title, "LVGL ADC DEMO");

    lbl_adc_x = lv_label_create(lv_scr_act(), lbl_title);
    lv_obj_set_pos(lbl_adc_x, 0, 30);
    lv_obj_set_size(lbl_adc_x, 64, 20);   
    lv_label_set_text(lbl_adc_x, "X:0000");

    lbl_adc_y = lv_label_create(lv_scr_act(), lbl_adc_x);
    lv_obj_set_pos(lbl_adc_y, 64, 30);   
    lv_label_set_text(lbl_adc_y, "Y:0000");
}
```
lvgl任务:
---
```
static void application_lvglTask_entry(void *arg)
{
    lv_init();
    /*Initialize for LittlevGL*/
    oled_init();

    /*Select display 1*/
    gui_label_create();

    while (1)
    {
      if (1 == aos_mutex_is_valid(&adc_mutex))
      {
            aos_mutex_lock(&adc_mutex, AOS_WAIT_FOREVER);
            lv_label_set_text_fmt(lbl_adc_x, "X:%d", adcRes);
            lv_label_set_text_fmt(lbl_adc_y, "Y:%d", adcRes);
            aos_mutex_unlock(&adc_mutex);
      }
      /* Periodically call the lv_task handler.
         * It could be done in a timer interrupt or an OS task too.*/
      lv_task_handler();
      aos_msleep(10);
      lv_tick_inc(1);
    }
}
```
## 三、 运行结果



## 四、 总结

4.1 反而是最基础的功能,遇到了很多的坑。

4.1.1 一开始使用了ADC的HAL库,运行结果不正确。折腾了好久,最后换成了csi方案,虽然hal里也是使用了csi接口来完成的。随后抽时间再试试。

4.1.2 无论是CSI接口还是HAL接口,一直掉坑的原因是官方文档对关键参数的解释和说明上,几乎就没有,另外就是接口库过多,没有统一的对这些接口的使用说明,然后在使用和选择上花费大量的时间。

4.2 AD的连续转换模式和dma模式的使用

连续转换是否能够一次完成两个通道的转换,这个需要随后再考证。

使用DMA的话,可以多次采集完成一些滤波算法。这里对数据不敏感,有时间再测试。

wangerxian 发表于 2022-4-6 15:56

<p>我还想能显示波形呢,那样更厉害~</p>

wo4fisher 发表于 2022-4-7 00:08

wangerxian 发表于 2022-4-6 15:56
我还想能显示波形呢,那样更厉害~

<p>使用chart组件?</p>

wangerxian 发表于 2022-4-7 09:34

wo4fisher 发表于 2022-4-7 00:08
使用chart组件?

<p>可以啊~试试呗。</p>
页: [1]
查看完整版本: [平头哥RVB2601创意应用开发]体验分享四:ADC 多通道测试+LVGL显示