252 views|0 replies

7

Posts

1

Resources
The OP
 

【Follow me Season 2 Episode 2】Achieve Task 2: Drive 12x8 dot matrix LEDs; Use DAC to generate sine waves and amplify the acquisition [Copy link]

 This post was last edited by eew_ljd6R2 on 2024-9-7 23:16

Hello everyone,

Today we will start to complete the first key task of Task 2 - driving a dot matrix screen composed of 12x8 LED lights .

The ingenuity of dot matrix screen :

  • Efficient control : The dot matrix screen can be fully controlled through only 10 pins , thanks to its unique dot matrix layout and multiplexing technology.
  • Hardware design : From the hardware schematic diagram, we can clearly see that through specific circuit logic, when pin 7 is high and pin 3 is low, LED1 can be lit; otherwise, LED2 can be lit.

Refresh strategy :

  • Column-by-column refresh : In order to effectively reduce the pin requirements and achieve smooth visual effects, we will adopt a column-by-column refresh strategy. This means that we will activate each column in turn at a very fast speed (in this scenario, we regard it as a "row" to conform to the common operation mode of the dot matrix screen), and at the same time, set the corresponding column (row) data through other pins.
  • Persistence of vision : Due to the persistence of vision effect of the human eye, this high-speed but orderly refresh process will make the LED lighting appear continuous rather than flickering.

Animation effect realization :

  • Frame data design : In order to create animation effects, we will design a series of frame data , each frame data represents a specific lighting state of the LED on the dot matrix screen.
  • Display control : By displaying these frames in sequence and precisely controlling the display time interval between each frame, we can present dynamically changing images, that is, animation effects.

Summarize :

By cleverly utilizing the multiplexing technology and high-speed refresh strategy of the dot matrix screen, we have successfully achieved full control of the 12x8 LED dot matrix screen with only 10 pins.

Arduino has developed an efficient API specifically for the dot matrix screen. By introducing Arduino_LED_Matrix.hthe library, developers can easily control the dot matrix screen. First, you need to create a dot matrix screen object, for example, name it ledMatrixand ArduinoLEDMatrixinstantiate it with a class:


cpp复制代码

ArduinoLEDMatrix ledMatrix;

Next, perform initialization settings to prepare to control a 12x8 dot matrix screen. This library allows you to use a 12*8 two-dimensional array to directly control each LED on the screen, where an array element of 1 means the LED is on, and a 0 means it is off.

In this way, by dynamically modifying the 0 and 1 in this two-dimensional array in the program, different screens can be easily displayed. This API design greatly simplifies the control logic of the dot matrix screen, allowing developers to focus more on the realization of creativity and content rather than the underlying hardware operations.

In summary, Arduino_LED_Matrixthe library officially provided by Arduino has brought unprecedented convenience to the development of dot matrix screens. Complex and varied display effects can be achieved through simple API calls and intuitive two-dimensional array control.

The official also developed a small plug-in that can create animations. You can see how to use it through the video below.

Below is the code for this task. The general process is to set an animation through the tool and load it in.

#include "Arduino_LED_Matrix.h"
#include <stdint.h>
#include "animation.h"
ArduinoLEDMatrix matrix;

void setup() {
  // put your setup code here, to run once:
 matrix.loadSequence(animation);
  matrix.begin();
  // turn on autoscroll to avoid calling next() to show the next frame; the parameter is in milliseconds
  // matrix.autoscroll(300);
  matrix.play(true);
}

void loop() {
  // put your main code here, to run repeatedly:

}



const uint32_t animation[][4] = {
	{
		0xfff00000,
		0x0,
		0x0,
		66
	},
	{
		0xfff00,
		0x0,
		0x0,
		66
	},
	{
		0xff,
		0xf0000000,
		0x0,
		66
	},
	{
		0x0,
		0xfff0000,
		0x0,
		66
	},
	{
		0x0,
		0xfff0,
		0x0,
		66
	},
	{
		0x0,
		0xf,
		0xff000000,
		66
	},
	{
		0x0,
		0x0,
		0xfff000,
		66
	},
	{
		0x0,
		0x0,
		0xfff,
		66
	}
};

Next, complete the second task. First, use the DAC to generate a sine wave.

DAC, the full name of Digital-to-Analog Converter, is an electronic device or circuit whose core function is to convert digital signals into corresponding analog signals. In modern electronic systems, DAC plays a vital role. It is a bridge connecting digital circuits and analog circuits, and provides a basis for data interaction between digital systems and analog systems.

DAC (Digital-to-Analog Converter) and PWM (Pulse Width Modulation) play different roles in electronic systems, and there are significant differences between them. Here are the main differences between DAC and PWM:

1. Function and principle

  • DAC : A DAC is an electronic device or circuit used to convert digital signals into analog signals. It receives discrete digital signals (such as binary code) and converts them into continuously variable analog signals (such as voltage or current). DACs are widely used in audio equipment, control systems, instrumentation, etc. as a bridge between digital circuits and analog circuits.
  • PWM : PWM is a technique for simulating continuous analog signals by adjusting the duty cycle of the signal. A PWM signal is a square wave with a fixed frequency but a variable duty cycle (i.e., the ratio of the duration of the high level to the period). By adjusting the duty cycle, PWM can simulate analog signals of different amplitudes. PWM is widely used in power supplies with high power conversion efficiency, motor control, audio amplification, and other fields.

2. Output characteristics

  • DAC : The output of DAC is a continuous analog signal, whose amplitude can change continuously within a certain range. The output signal of DAC is of high quality, capable of restoring the details and dynamic characteristics of audio, and is suitable for occasions requiring high-fidelity audio output.
  • PWM : The output of PWM is a square wave signal, the amplitude of which does not change continuously, but can be converted into an approximate analog signal through filtering and other processing. PWM has high output efficiency and low power consumption, and is suitable for occasions such as audio drivers that require high efficiency and low power consumption.

3. Application areas

  • DAC : DAC is widely used in audio equipment (such as CD players, power amplifiers), control systems (such as industrial automation control), instrumentation (such as oscilloscopes, spectrum analyzers), etc. In these fields, DAC is responsible for converting digital signals into analog signals for subsequent processing or output.
  • PWM : PWM is widely used in power supplies with high power conversion efficiency (such as switching power supplies), motor control (such as motor drivers), audio amplification (such as digital audio amplifiers), etc. In these fields, PWM controls the on and off of power components by adjusting the duty cycle, thereby achieving high-efficiency power conversion or audio amplification.

4. Accuracy and resolution

  • DAC : The accuracy and resolution of a DAC depends on the number of bits (e.g. 8-bit, 12-bit, 16-bit, etc.). The higher the number of bits, the greater the number of analog signal values that the DAC can output, and the higher the accuracy and resolution.
  • PWM : The accuracy and resolution of PWM are limited by the frequency and duty cycle adjustment accuracy. Although the analog accuracy can be improved by increasing the frequency and duty cycle adjustment accuracy of PWM, it is usually difficult to achieve the high accuracy and resolution of DAC.

In summary, there are significant differences between DAC and PWM in terms of function, principle, output characteristics, application areas, accuracy and resolution.

In the R3 version, all outputs are implemented based on PWM technology. However, in the R4 version, we introduced a DAC (digital analog converter) on the A pin. Although the function called by its output is still analogWrite(), it actually provides an analog signal generation mechanism different from PWM.

Let's analyze this function.


void analogWrite(pin_size_t pinNumber, int value)
{
#if (DAC12_HOWMANY > 0) || (DAC8_HOWMANY > 0)
  if (IS_DAC(pinNumber)) {
    auto cfg_dac = getPinCfgs(pinNumber, PIN_CFG_REQ_DAC);
    if(IS_DAC_8BIT(cfg_dac[0])) {
      #if DAC8_HOWMANY > 0
      if(GET_CHANNEL(cfg_dac[0]) < DAC8_HOWMANY) {
        _dac8[GET_CHANNEL(cfg_dac[0])].analogWrite(value);
      }
      #endif
    }
    else {
      if(GET_CHANNEL(cfg_dac[0]) < DAC12_HOWMANY) {
        _dac12[GET_CHANNEL(cfg_dac[0])].analogWrite(value);
      }
    }
    return;
  }

Here we can see that IS_DAC() is used to determine whether it is a DAC pin. If it is, the DAC output method is used. If not, the ordinary PWM method is used.

Therefore, we can use the `sin()` function to generate a sine wave, and use the variable `a` as a factor. According to what we learned in high school, the function form of the sine wave is `f(x) = a * sin(kx + b)`. Among them, `a` represents the amplitude, which we will keep unchanged for now. Then, we can adjust the period and phase of the sine wave by changing the values of `k` and `b` respectively. Next, we will achieve real-time update of the printed function graph by changing the values of these two parameters in real time. Now, let's start to implement this part.

Code to generate DAC sine wave


  analogWriteResolution(12);


 // put your main code here, to run repeatedly:
  a+=0.01;
  if(a>2*PI)
  {
    a=0;
  }
  
  float out=map_float(sin(K*a+B),-1,1,0,4096);
  analogWrite(DAC, out);

It is important to note here that the `analogWriteResolution()` function changes the accuracy of the DAC (digital-to-analog converter). I will explain this in detail in the video below. In addition, the `map_float` function is similar to the `map` function. Since the output range of the `sin` function is -1 to 1, we need to map it to the range of 0 to 4096.

Next we configure the operational amplifier opamp. It has three input ports: +, -, and output. + is A1, - is A2, and output is A3. The official website provides a typical circuit and calculation formula.

Here we use a typical circuit and the input is the output connection method is output connection - input

This is configured as high-speed mode

OPAMP.begin(OPAMP_SPEED_HIGHSPEED);

Finally, read the ADC and print it. I use A5 here. This is very simple. Receive and print

 int reading = analogRead(A5);
  //a=map(reading,0,4096,0,2*3.1415926);
  Serial.println(reading);

Next, I will show you how to change the values of `k` and `b`. The method I use is to send data through the serial port, and the data format is "A:15". After receiving the string, I will parse it to extract the data before and after the colon, so as to get `A` and `15`, and then change the corresponding values accordingly.

The code is as follows

String str="";
  if (Serial.available() > 0) {  
    // 读取一个字节的数据,并将其转换为字符后添加到receivedString中  
    // 注意:这里假设我们不知道字符串何时结束,因此持续读取直到超时或检测到特定的结束字符  
    char incomingByte = Serial.read();  
      
    // 检查是否是字符串的结束符(例如换行符'\n')  
    // 注意:根据你的发送方,结束符可能不同  
    if (incomingByte == '\n') {  
      // 如果是结束符,则不将其添加到receivedString中,而是直接处理字符串  
      // 在这里,我们只是简单地打印它  
     parseString(receivedString);
        
      // 清空receivedString,为接收下一个字符串做准备  
      receivedString = "";  
    } else {  
      // 如果不是结束符,则将其添加到receivedString中  
      receivedString += incomingByte;  
    }  
  }  





void parseString(String input) {  
  // 查找冒号在字符串中的位置  
  int colonIndex = input.indexOf(':');  
  if (colonIndex == -1) {  
    Serial.println("Input format is incorrect. Missing colon.");  
    return;  
  }  
    
  // 提取标识符(冒号之前的部分)  
  String identifier = input.substring(0, colonIndex);  
    
  // 提取数字(冒号之后的部分),注意substring的第二个参数是结束索引(不包含),所以我们需要+1  
  String numberStr = input.substring(colonIndex + 1);  
  int number = numberStr.toInt(); // 将字符串转换为整数  
    
  if(identifier=="K")
  {
    K=number;
  }
  if(identifier=="B")
  {
    B=number;
  }
}  

Complete code

#include <OPAMP.h>
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
  analogReadResolution(14);
  analogWriteResolution(12);

}
double a=0;
String receivedString = ""; 
int K=1;
int B=0;
void loop() {
  // put your main code here, to run repeatedly:
  a+=0.01;
  if(a>2*PI)
  {
    a=0;
  }
  
  float out=map_float(sin(K*a+B),-1,1,0,4096);
  analogWrite(DAC, out);
  // Serial.println(out);
  int reading = analogRead(A5);
  //a=map(reading,0,4096,0,2*3.1415926);
  Serial.println(reading);
  //Serial.print(",");
  //Serial.println(out);
  String str="";
  if (Serial.available() > 0) {  
    // 读取一个字节的数据,并将其转换为字符后添加到receivedString中  
    // 注意:这里假设我们不知道字符串何时结束,因此持续读取直到超时或检测到特定的结束字符  
    char incomingByte = Serial.read();  
      
    // 检查是否是字符串的结束符(例如换行符'\n')  
    // 注意:根据你的发送方,结束符可能不同  
    if (incomingByte == '\n') {  
      // 如果是结束符,则不将其添加到receivedString中,而是直接处理字符串  
      // 在这里,我们只是简单地打印它  
     parseString(receivedString);
        
      // 清空receivedString,为接收下一个字符串做准备  
      receivedString = "";  
    } else {  
      // 如果不是结束符,则将其添加到receivedString中  
      receivedString += incomingByte;  
    }  
  }  


}
//AB

void parseString(String input) {  
  // 查找冒号在字符串中的位置  
  int colonIndex = input.indexOf(':');  
  if (colonIndex == -1) {  
    Serial.println("Input format is incorrect. Missing colon.");  
    return;  
  }  
    
  // 提取标识符(冒号之前的部分)  
  String identifier = input.substring(0, colonIndex);  
    
  // 提取数字(冒号之后的部分),注意substring的第二个参数是结束索引(不包含),所以我们需要+1  
  String numberStr = input.substring(colonIndex + 1);  
  int number = numberStr.toInt(); // 将字符串转换为整数  
    
  if(identifier=="K")
  {
    K=number;
  }
  if(identifier=="B")
  {
    B=number;
  }
}  

float map_float(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

I used VOFA serial port assistant to print the final result picture because it is a bit troublesome to change the Arduino serial port oscilloscope.

The middle part shows the changes of K and B values. The video below is a detailed tutorial and results, as well as some other knowledge that is not easy to introduce on paper.



This post is from DigiKey Technology Zone
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list