用STEP Pico开发板制作的电压表
2023寒假一起练 STEP Pico 树莓派 rp2040 arduino oled U8G2 ADC WS2812B 伪彩色
标签
嵌入式系统
MPU
测试
显示
aramy
更新2023-03-28
340

硬件介绍:2023寒假一起练平台(1)基于STEP Pico 的嵌入式系统学习平台。是一个硬禾设计制造的树莓派Pico。分为两个部分,硬禾版本树莓派Pico核心模块,较树莓派Pico,修改了micro USB为type-C口,增加了一个run按键,添加了4个WS2812B的LED。扩展板上集成了12个WS2812B RGB三色灯;1个姿态传感器;1个128*64 OLED显示屏;1个蜂鸣器;1个可调电位计(用于电压表);1路音频信号输入(用于示波器);8位R-2R电阻网络构成的DAC(用于DDS信号发生器)。

任务选择:这次我选择的项目4 - 制作一个电压表。具体要求:利用板上的电位计调节电压从0-3.3V之间变化,在OLED显示屏上显示电压值,可以以数字的方式,也可以以图形的方式来显示。实现方式:调节电位计产生0-3.3V之间变化的电压,树莓派Pico内部的ADC对该电压进行采集,得到0-4095之间的数值,经过计算以后对应到相应的电压值,再通过OLED显示屏显示出来。
这块板块支持MicroPython、Arduino、C/C++。电子森林提供了非常详细的MicroPython的教程。这次想尝试一下使用Arduino来实现任务。开发工具选择vscode+platformio。整体流程很简单,如下图。
Fj4I5pJXSpdfRp6GuwgtaFTSGuAb
任务实现:要实现任务,首先是数据来源。即获得电位器的电压值。查看电路图可知电位器接在GPIO28脚,电压范围0~3.3v。直接调用Arduino中的ADC函数analogRead(),即可获得该通道的ADC值,这里的值并不是直接返回电位器上的电压值,而是处理过的数值,其数值范围为0-1023。这里有一点点疑惑,使用Mpy读取ADC值是0-65535;那么RP2040的ADC的分辨率到底是多少位的呢?查了官方的文档:明确了rp2040的ADC位500ksps,12-bit分辨率。这样Arduino的函数实际是降低了ADC的分辨率,不知道应该如何设置能够获得到12位分辨率的值。这里姑且先使用10位分辨率的ADC值。将获得的ADC映射到0~3.3v电压上。

float readVoltage(uint16_t *adcval)
{
  // 读取ADC的值 范围 0~1024
  uint16_t val = analogRead(ADCPIN);
  *adcval = val;
  return (float)val * 3.3 / 1024.0;
}

拿到了电压值,接下来就是展示了。硬件上板子提供了一块128x64的oled显示屏。使用的是SPI接口。这里使用了Arduino的U8g2库。如果手工驱动屏幕,那需要对要显示的内容取模,然后逐一显示,还是比较麻烦的。而U8g2库则可以很轻松地支持起这个Oled显示屏,普通的字符显示变得很容易了。
这里主要需要显示的内容为当前的电压值。我选用24像素的字体,来显示电压值。额外地将ADC读取的原始值、当前电压索占百分比也同时显示出来,就是用小一点的字体(16像素)来显示。

成功显示了电位器的电压值,总觉得有显示有些单调。于是看着Oled四周有一圈WS2812B,一共12颗。WS2812B是一个单总线工作的全彩LED灯,在各种灯带中常见这个LED。能够做成很绚丽的光电效果。这里使用WS2812FX的库,来驱动WS2812B。控制着12个LED灯实现单个灯旋转闪烁的效果。颜色使用电压对应的伪彩色。即将电位器的电压0~3.3V映射到RGB的全色域。表现为从蓝色到紫色。这样就可以直观地用颜色表示当前电压了。

// 浮点数转颜色  伪彩色
float MinVol=0.0 , MaxVol=3.3, a, b, c, d;
void Getabcd() { 
  a = MinVol + (MaxVol - MinVol) * 0.2121;
  b = MinVol + (MaxVol - MinVol) * 0.3182;
  c = MinVol + (MaxVol - MinVol) * 0.4242;
  d = MinVol + (MaxVol - MinVol) * 0.8182; 
}
uint32_t GetColor(float val) {
  byte red = 0, green = 0, blue = 0;
  red = constrain(255.0 / (c - b) * val - ((b * 255.0) / (c - b)), 0, 255);
  if ((val > MinVol) & (val < a)) {
    green = constrain(255.0 / (a - MinVol) * val - (255.0 * MinVol) / (a - MinVol), 0, 255);
  } else if ((val >= a) & (val <= c)) {
    green = 255;
  } else if (val > c) {
    green = constrain(255.0 / (c - d) * val - (d * 255.0) / (c - d), 0, 255);
  } else if ((val > d) | (val < a)) {
    green = 0;
  }

  if (val <= b) {
    blue = constrain(255.0 / (a - b) * val - (255.0 * b) / (a - b), 0, 255);
  }  else if ((val > b) & (val <= d)) {
    blue = 0;
  }  else if (val > d) {
    blue = constrain(240.0 / (MaxVol - d) * val - (d * 240.0) / (MaxVol - d), 0, 240);
  }

程序主体部分就很简单了,不停地循环查询电位器的电压值,然后显示,再去控制LED灯,循环此过程。

void setup()
{
  Serial.begin(115200);
  u8g2.begin(); // 选择U8G2模式,或者U8X8模式
  ws2812fx.init();
  ws2812fx.setBrightness(100);
  ws2812fx.setSpeed(1000);
  ws2812fx.setColor(GREEN);
  // ws2812fx.setMode(FX_MODE_STATIC);
  ws2812fx.setMode(13);
  ws2812fx.start();
}
void loop()
{
  uint16_t adcval;
  char str[60];
  ws2812fx.service();
  float voltage = readVoltage(&adcval);
  Serial.print(adcval);
  Serial.print("    ");
  Serial.print(voltage);
  Serial.print("    ");
  Serial.println();

  u8g2.clearBuffer(); // 清除内部缓冲区
  u8g2.setFont(u8g2_font_ncenB24_tr);
  sprintf(str, "%1.1f%s", voltage, "V");
  u8g2.drawStr(35, 30, str); // write something to the internal memory
  u8g2.setFont(u8g2_font_helvR12_tr);
  sprintf(str, "%4d      %3d%s", adcval, int(adcval / 10.23), "%");
  u8g2.drawStr(20, 60, str);
  u8g2.sendBuffer(); // transfer internal memory to the display
  delay(100);
  Getabcd();
  ws2812fx.setColor(GetColor(voltage));
}

FkmOqoxh1f0WPZ2J8yg3AMSBCtBY

Fi2cOzAVJySGHyE3TE34SQGXJ0Mx

FgiKjXlAXpHcAlLsPTkSsQdizWsH

 

心得体会:非常感谢电子森林举办的寒假一起练活动;感谢硬禾学堂提供的课程。课程很精彩、板子很好玩!
 


附件下载
pico2023.zip
团队介绍
瞎捣鼓小能手
团队成员
aramy
单片机业余爱好者,瞎捣鼓小能手。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号