[作品提交] 【Follow me第二季第2期】+LED矩阵、DAC、放大器、AD

王嘉辉   2024-9-7 01:06 楼主
上一篇简单学习了Arduino R4 WIFI的GPIO的操作,以及串口打印数据的操作,这篇将记录学习这个板子上特殊的外设LED矩阵,以及模拟相关DAC、ADC和放大器相关的内容。
、板载LED矩阵
首先应该包含Arduino提供的矩阵库文件#include "Arduino_LED_Matrix.h"
然后在这个文件中有一个ArduinoLEDMatrix类,我们利用这个类定义一个新的对象matrix。代码实现为ArduinoLEDMatrix matrix;
初始化矩阵matrix.begin();
定义矩阵显示,矩阵的显示无非就是控制每个LED处于高电平还是低电平,当对应的LED为高电平时,LED点亮,与此同时矩阵中对应的位置数字为1。反之为低电平,LED熄灭,矩阵对应的位置数字为0。
Arduino R4 WIFI的板子上的LED矩阵为8*12,因此我们定义一个二维数组用来存放显示图形的数据。这里设置了三个图形,分别是笑脸、眨眼和哭脸。
uint8_t smile[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

uint8_t wink[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

uint8_t cry[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

 

最后调用matrix.renderBitmap(smile, 8, 12);函数便可以实现将数组数据加载到LED矩阵中去,在每个表情切换中间加上适当的延时,实现表情的显示。

同样的可以进行汉字、数字等的显示,更改对应的数组信息即可。
完整代码:
#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

void setup()
{
Serial.begin(115200);
matrix.begin();
}

uint8_t smile[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

uint8_t wink[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

uint8_t cry[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

void loop()
{
matrix.renderBitmap(smile, 8, 12);
delay(1000);
matrix.renderBitmap(wink, 8, 12);
delay(1000);
matrix.renderBitmap(cry, 8, 12);
delay(1000);
}

 

视频演示:
98a704f311287c9b4b56ff070b1cc1ae

、DAC产生正弦波形
DAC就是模数转换器,可以将数字信号转换为模拟信号,这个功能可以用来制作函数发生器也可以用来驱动蜂鸣器实现音频的播放,相比于PWM频率控制,可以实现更加连续的波形产生,比如正弦波、锯齿波等等。
首先是驱动DAC能够产生一个稳定的电压信号,然后通过每次更换输入的数字值,从而改变每次输出的电压信号,让电压信号的变化遵循正弦信号的变化,即可实现正弦信号的生成。下面我们一步一步来实现。
通过调用函数analogWriteResolution(8);设置了DAC的分辨率为8bit。然后调用函数analogWrite(DAC, 具体数值(0-255));就可以实现产生一个稳定的直流电压信号。我们分别设置数值为100和150来查看电压是否会发生变化。当为100时,使用万用表测量的数据为1.76V,当为150时,使用万用表测量的数据为2.637V。当为255时,即可以设置的最大数字时,电压表显示的电压值为4.46。因此可以得出当DAC设置为8bit模式时,每一个值代表的电压大约为0.01754V,根据你想要的电压值,除于该数值便可以得到要输入的数值。比如需要3V电压值,3/0.01754=171(省略小数位),输入171,则可以得到大约为3V的电压值。
void setup() 
{
  analogWriteResolution(8);  // set the analog output resolution to 12 bit (4096 levels)
}

void loop() 
{
  analogWrite(DAC, 171);  // write the selected waveform on DAC0
}

image.png  

 

那么我们将产生正弦信号的数值依次存放在数组中,间隔一定的时间(与频率有关)将数组的每一位依次传入该函数中,使用DAC将数据输出成模拟信号,便可以实现正弦波的生成。同时还找到一个锯齿波的数组,但是锯齿波的数据仅有120位,且要求DAC的分辨率为12,因此需要修改analogWriteResolution(8);中的8改为12,analogWrite(DAC, wave_sin);中的wave_sin改为waveformsTable,同时将if (i == 256)中的256修改为120即可。

Waves.h代码
#ifndef _Waves_h_
#define _Waves_h_

static int waveformsTable[120] = {

    0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x110, 0x132, 0x154,
    0x176, 0x198, 0x1ba, 0x1dc, 0x1fe, 0x220, 0x242, 0x264, 0x286, 0x2a8,
    0x2ca, 0x2ec, 0x30e, 0x330, 0x352, 0x374, 0x396, 0x3b8, 0x3da, 0x3fc,
    0x41e, 0x440, 0x462, 0x484, 0x4a6, 0x4c8, 0x4ea, 0x50c, 0x52e, 0x550,
    0x572, 0x594, 0x5b6, 0x5d8, 0x5fa, 0x61c, 0x63e, 0x660, 0x682, 0x6a4,
    0x6c6, 0x6e8, 0x70a, 0x72c, 0x74e, 0x770, 0x792, 0x7b4, 0x7d6, 0x7f8,
    0x81a, 0x83c, 0x85e, 0x880, 0x8a2, 0x8c4, 0x8e6, 0x908, 0x92a, 0x94c,
    0x96e, 0x990, 0x9b2, 0x9d4, 0x9f6, 0xa18, 0xa3a, 0xa5c, 0xa7e, 0xaa0,
    0xac2, 0xae4, 0xb06, 0xb28, 0xb4a, 0xb6c, 0xb8e, 0xbb0, 0xbd2, 0xbf4,
    0xc16, 0xc38, 0xc5a, 0xc7c, 0xc9e, 0xcc0, 0xce2, 0xd04, 0xd26, 0xd48,
    0xd6a, 0xd8c, 0xdae, 0xdd0, 0xdf2, 0xe14, 0xe36, 0xe58, 0xe7a, 0xe9c,
    0xebe, 0xee0, 0xf02, 0xf24, 0xf46, 0xf68, 0xf8a, 0xfac, 0xfce, 0xff0
  

};

static int wave_sin[256] = {
  0x80,0x83,0x85,0x88,0x8A,0x8D,0x8F,0x92,   
  0x94,0x97,0x99,0x9B,0x9E,0xA0,0xA3,0xA5,   
  0xA7,0xAA,0xAC,0xAE,0xB1,0xB3,0xB5,0xB7,   
  0xB9,0xBB,0xBD,0xBF,0xC1,0xC3,0xC5,0xC7,   
  0xC9,0xCB,0xCC,0xCE,0xD0,0xD1,0xD3,0xD4,   
  0xD6,0xD7,0xD8,0xDA,0xDB,0xDC,0xDD,0xDE,   
  0xDF,0xE0,0xE1,0xE2,0xE3,0xE3,0xE4,0xE4,   
  0xE5,0xE5,0xE6,0xE6,0xE7,0xE7,0xE7,0xE7,   
  0xE7,0xE7,0xE7,0xE7,0xE6,0xE6,0xE5,0xE5,   
  0xE4,0xE4,0xE3,0xE3,0xE2,0xE1,0xE0,0xDF,   
  0xDE,0xDD,0xDC,0xDB,0xDA,0xD8,0xD7,0xD6,   
  0xD4,0xD3,0xD1,0xD0,0xCE,0xCC,0xCB,0xC9,   
  0xC7,0xC5,0xC3,0xC1,0xBF,0xBD,0xBB,0xB9,   
  0xB7,0xB5,0xB3,0xB1,0xAE,0xAC,0xAA,0xA7,   
  0xA5,0xA3,0xA0,0x9E,0x9B,0x99,0x97,0x94,   
  0x92,0x8F,0x8D,0x8A,0x88,0x85,0x83,0x80,   
  0x7D,0x7B,0x78,0x76,0x73,0x71,0x6E,0x6C,   
  0x69,0x67,0x65,0x62,0x60,0x5D,0x5B,0x59,   
  0x56,0x54,0x52,0x4F,0x4D,0x4B,0x49,0x47,   
  0x45,0x43,0x41,0x3F,0x3D,0x3B,0x39,0x37,   
  0x35,0x34,0x32,0x30,0x2E,0x2D,0x2C,0x2A,   
  0x29,0x28,0x26,0x25,0x24,0x23,0x22,0x21,   
  0x20,0x1F,0x1E,0x1D,0x1D,0x1C,0x1C,0x1B,   
  0x1B,0x1A,0x1A,0x1A,0x19,0x19,0x19,0x19,   
  0x19,0x19,0x19,0x19,0x1A,0x1A,0x1A,0x1B,   
  0x1B,0x1C,0x1C,0x1D,0x1D,0x1E,0x1F,0x20,   
  0x21,0x22,0x23,0x24,0x25,0x26,0x28,0x29,   
  0x2A,0x2C,0x2D,0x2F,0x30,0x32,0x34,0x35,   
  0x37,0x39,0x3B,0x3D,0x3F,0x41,0x43,0x45,   
  0x47,0x49,0x4B,0x4D,0x4F,0x52,0x54,0x56,   
  0x59,0x5B,0x5D,0x60,0x62,0x65,0x67,0x69,   
  0x6C,0x6E,0x71,0x73,0x76,0x78,0x7B,0x7D
};

#endif

主函数代码

#include "Waves.h"

int i = 0;

void setup() 
{
  analogWriteResolution(8);  // set the analog output resolution to 12 bit (4096 levels)
}

void loop() 
{
  analogWrite(DAC, wave_sin[i]);  // write the selected waveform on DAC0
  i++;

  if (i == 256)  // Reset the counter to repeat the wave
    i = 0;
  delayMicroseconds(10);  // Hold the sample value for the sample time
}
image.png image.png    
、板载放大器
Arduino R4 WIFI板子上自带一个内置的放大器,可以将A1作为正向输入、A2作为反向输入、A3作为输出。因此设计一个放大倍数两倍的同相比例放大器,来放大我们产生的正弦信号。
想要使用内置的放大器,首先要引入一个库,#include <OPAMP.h>然后开启放大器即可,使用函数OPAMP.begin(OPAMP_SPEED_HIGHSPEED);即可开启放大器。
除此之外的代码analogWrite(DAC, wave_sin/2);仅在此处加了一个除2的操作,若不加除2放大后的波形会出现削顶失真,当然也可以通过更改数组的数值进行调整。其余的均与DAC代码保持一致,包括Waves.h库文件。
#include "Waves.h"
#include <OPAMP.h>

int i = 0;

void setup() 
{
  OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
  analogWriteResolution(8);  // set the analog output resolution to 12 bit (4096 levels)
}

void loop() 
{
  analogWrite(DAC, wave_sin[i]/2);  // write the selected waveform on DAC0
  i++;

  if (i == 256)  // Reset the counter to repeat the wave
    i = 0;
  delayMicroseconds(10);  // Hold the sample value for the sample time
}

 

其原理可由该图来解释。该图构成一个简易的同相比例放大器,其中放大倍数由黄色的公式给出。可以调整两个电阻的大小,更改放大倍数。红色为放大电路主体,将A0和A1短接,即将DAC产生的模拟信号输入到放大器的正向输入端,输出和反向输入端构成反馈。蓝色为波形的示意,A1输入的正弦峰值为1V,A3输出的正弦峰值为2V。
实物搭建较为简陋,但是通过示波器,可以明显看出输出波形相较于输入波形有了明显的放大,且放大倍数大约在2倍。
image.png   image.png  
image.png   image.png  
、ADC采集数据并使用串口打印绘制波形。
ADC就是模数转换器,其工作方式与DAC恰好相反。可以将输入的模拟信号转换为数字信号,然后进行数字上的处理,更适应这个数字化发展的趋势。
在硬件上的连接,需要将放大器的A3输出引脚连接在A4的ADC采集引脚上。
使用ADC首先需要初始化ADC,调用函数analogReadResolution(8); 。并使用函数int reading = analogRead(A4);将A4引脚上的模拟数值转换为数字数值并存储在reading变量中。然后通过串口进行数据的打印以及波形图的绘制。。
#include "Waves.h"
#include <OPAMP.h>

int i = 0;

void setup() 
{
  OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
  analogWriteResolution(8);  // set the analog output resolution to 12 bit (4096 levels)
  analogReadResolution(8); //change to 14-bit resolution
  Serial.begin(9600);
}

void loop() 
{
  analogWrite(DAC, wave_sin[i]/2);  // write the selected waveform on DAC0
  i++;

  if (i == 256)  // Reset the counter to repeat the wave
    i = 0;

  int reading = analogRead(A4); // returns a value between 0-16383

  delayMicroseconds(10);  // Hold the sample value for the sample time

  Serial.print(reading);
  Serial.print("\n");
}

 

005825liks3oiqpw0sh04q.png

005825i0lu2oeb1bcguzau.png

回复评论 (1)

DAC、ADC和放大器几个试验测试还行,波形都出来了,谢谢分享

点赞 (1) 2024-9-9 07:32
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复