AM modulation display with Nextion, Arduino and MCP4461 DigiPot

Hello all and happy new year.

I’m new to Arduino, been working on this sketch and need advice at this point. I’ll explain the best I can.

The sketch is for an AM Modulation Meter which is displayed on a Nextion Enhanced display on a Progress Bar with a value range of 0 to 100. In AM modulation there are Positive and Negative peaks. Here we are working with the positive peaks only.

Initially, when the carrier is first present the Arduino sees an incomingCarrierLevel DC signal on pin A3 ranging between 0 and 5 volts.

(A). Waits 1 second and if the incomingCarrierLevel DC signal has not changed value during this 1 second, the modulationRange scaling (0 to 300) must first be calibrated with this value to auto map the incomingCarrierLevel (0 to 1023) to always be 25 (same as 1/12 or ~.083%) within one second.

modulationRange must be calibrated to properly display the upcoming modulation peak values.

For example:

Map the incomingCarrierLevel (0 to 1023) to the modulationRange (0 to 300) and give it the value of 25.

[code]

modulationRange = map ( incomingCarrierLevel, 0, 1023, 0, 300 ); //need to assign value of 25 or .083% of 300, to the modulationRange with a scale ranging from 0 to 300.

At this point modulationRange (0 to 300) should hold the value of 25 (.083% full) which must be mapped and displayed on the modulationMeter range in the Nextion display at 8.3 on the scale of 0 to 100. At this time a red marker (carMarker) must flash at the corresponding position at 8.3 (.083% of the 0 to 100 Nextion Progress Bar scale).

For example:

Map the modulationRange (0 to 300) to the modulationMeter (0 to 100) on the Nextion display.

[code]

modulationMeter = map ( modulationRange, 0, 300, 0, 100 ); //need to assign value of 8.3 or .083% of 100, to the modulationMeter with a scale ranging from 0 to 100.

The mapped scale and value of the modulationRange must be held as reference to properly display the upcoming modulation peak values during this loop. The loop must exit when the modulation stops for one second, at this time loop and auto map the incomingCarrierLevel DC signal on pin A3 again to 25 of the modulationRange (0 to 300), map and display on the modulationMeter on the Nextion display and loop again when the modulation ends and keep repeating this process.

While in the loop, peak modulation values in modulationMeter must be displayed on the Nextion Progress Bar with the scaling ratio set within the loop right after the first second of the incomingCarrierLevel DC signal above (A).

Negative modulation must also be displayed on a second progress bar on the Nextion display. Implementing should be like the above so we will need two meters. For now I’ll like to focus on getting the positive modulation meter running first.

In conclusion, the process seems rather simple, get the carrier value sample for one second, set the scaling factor accordingly and display the modulation.

BTW: If anyone knows how to write to the non-volatile registers of the MCP4461 digital pot, please share the information. I have contacted Microchip and they have not been able to provide a code sample and the few libraries available for the MCP series of DigiPots are very limited with no sample code and with errors. I had to change and tweak the one I’m using to get it to work only on the volatile wipers and use the Nextion EEPROM to save the slider positions and load them at POR, send them to Arduino to send to the DigiPot. MCP4461 library at GitHub. If anyone needs mine, let me know and I’ll post it. I'm sure there is an easier method to accomplish this task and know this code is nowhere near perfect due to my lack of experience with programming, but always been a fan of constructive criticism. Thank you for your time and help in advanced..

=>My code:

#include <MYMCP4461.h>              //MCP4461 Digital Potentiometer(DigiPot) library
MYMCP4461 myMCP4461 = MYMCP4461();  
int RFInputPin(A3);                 //RF volt sample input signal

void setup() {
Serial.begin(38400);
myMCP4461.setMCP4461Address(47);    //set the I2C address for the DigiPot 
myMCP4461.begin();                  //Begin Digipot functions
pinMode(A3,INPUT);                  //Set analog pin 3 as an input
delay(100);
}
void loop() {modulation();} // Other loops omited for simplicity

void modulation(){               //Modulation meter loop
unsigned long currentMill = 0;  
int interval = (1000); 
int incomingCarrierLevel;        //Vlue at pin A3 (RF volt sample, 0 to 1023)
int modulationRange(0);          //Holds mapped value of "inputSignal" 0, 1023 mapped to 0, to 100
int car1In(0);
int inputCar1(0);
int carrier1(0);
int car2In(0);
int inputCar2(0);
int carrier2(0);
int mod1In(0);
int inputMod1(0);
int mod1(0);
int mod2In(0);
int inputMod2(0);
int mod2(0);
int j0ValCar;
int j0ValMod;
int j3Val;
int carMarker;

incomingCarrierLevel = analogRead(RFInputPin);     //Read DC voltage 0 to 5 volts pin A3
modulationRange=(100./1023.)*incomingCarrierLevel; //Convert/map 1023 scale to 100 scale

if (modulationRange >= 1) {                        //If detected voltage is greater than 1 continue
 car1In = analogRead(RFInputPin);                  //Assign RFInputPin value to car1In
 if(car1In == 0){j0ValCar=0; j0ValMod=0;}          //If car1In is 0 make sure j0 carrier and modulation value are 0 
  
  inputCar1=(100./1023.)*car1In;                   //Assign and map car1In value to inputCar1
  carrier1 = inputCar1;                            //Assign value of inputCar1 to carrier1   
  
   if(millis() > (currentMill + interval)){        //Wait 1 second to see if the carrier1 value doesn't change 
   currentMill = millis();                         //when compared to the carrier2 value on line 53
 
   car2In = analogRead(RFInputPin);                //Assign RFInputPin value to car2In realtime after the delay on line 46 to compare at line 53
   inputCar2=(100./1023.)*car2In;                  //Assign and map car2In value to inputCar2 (independent of car1In)
   carrier2 = inputCar2;                           //Assign value of inputCar2 to carrier2 
   
    if (carrier1 == carrier2) {                    //if after 1 second carrier1 is same value as carrier2 do the below
     j0ValCar = map(carrier1, 0, carrier2, 0, 100); //Map Nextion Progress Bar from 0 to the carrier2 value, and map it to j0ValCar at .083% or 8.3 on the 0 to 100 scale on Nextion
     j3Val= (carMarker, j0ValCar);                 //Assign carrier value to flashing carrier marker at the 8.3 mark in the scale of 0 to 100
     
     mod1In = analogRead(RFInputPin);              //Get modulation                                       
     inputMod1=(100./1023.)*mod1In;                //Assign and map mod1In value to inputMod1 
     mod1 = inputMod1;                             //Assign value of inputMod1 to mod1   

     j0ValMod = map(mod1, 0, mod2, 0, 100);        //Map mod1 with the scalling factor set on line 54 by carrier value mapped to .083% of the 0 to 100 scale     
    
    if(millis() > (currentMill + 100)){            //Count to 100 ms to send carrier value to Nextion within this time range 
     currentMill = millis();  
     Serial.print ("j0.val=");                     //Send the destination to write on Nextion (j0 Progress Bar)
     Serial.print (j0ValCar);                      //Send carrier value to the Nextion display within the 100 milliseconds                  
     Serial.write(0xff);                           //Required block of 3 ff packets at the end of each transmission to Nextion
     Serial.write(0xff);  
     Serial.write(0xff);
     Serial.print ("j3.val=");                     //Send the destination to write to on Nextion (flashing marker on j3 Progress Bar, superimposed on j0)
     Serial.print (j3Val);                         //Send marker value to the Nextion display within the 100 milliseconds
     Serial.write(0xff);                           //Required block of 3 0xff packets at the end of each transmission to Nextion
     Serial.write(0xff);  
     Serial.write(0xff);
    }else{
      Serial.print ("j0.val=");                   //Send the destination to write the modulation values on Nextion (j0 Progress Bar)
      Serial.print (j0ValMod);                    //Send modulation values to the Nextion display.
      Serial.write(0xff);                         //Required block of 3 0xff packets at the end of each transmission to Nextion
      Serial.write(0xff);  
      Serial.write(0xff);
  } 
 } 
    else if (mod1<1){                            //if signal ends, loop and wait for next carrier and start all over
    return;}
  }
 }
}

have you had a look at the Arduino library for MCP4461 Quad digital potentiometers from Microchip
there are number of MCP4461 libraries on github - do a web search for github MCP4461

Hi,

Thanks for your response.

The below code will allow to test all the 4 wipers volatile and non-volatile by uncommenting / uncommenting the lines. I've spent over 2 months trying to figure it out.

I've downloaded all the libraries available and non of them, even without them, writing the code and sending it without using the libraries, the MCP4461 will not send back the acknowledge bit when writing to the non-volatile wipers. Not sure what the procedure / trick is like or how they do it in the commercial world, I have read all 100 pages of the datasheet many times over and can't figure it out.

But primarily the issue with the modulation meter is of main concern, I've managed to save the wiper settings in the Nextion EEPROM and loading them in a timer event within the Nextion.

Thanks again..

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        // I2C Digital Potentiometer
//here we are using the MCP4461 library for the MCP4462

//#include <MCP4461.h>
#include <Wire.h>
//#define Addr 0x2F
// Instantiate objects used in this project
//MCP4461 myMCP4461; 

//declare an instance of MCP4461 with Device addr 0x2f ////0x2c = (B00101100, 0x2d = B00101101, 0x2e = B00101110, 0x2f = 00101111
//MCP4461 digiPot1(0x2f);   //same as decimal:47, same as:00101111 same as:( 0101 111 ), ***ie, both A0 & A1 pins pulled high by internal resistor (disconnected)***
//MCP4461 digiPot1(0x2e); //***A0 pin pulled low, A1 pin pulled high or disconnected***
//MCP4461 digiPot1(0x2d); //***A0 pin pulled high or disconnected, A1 pin pulled low***
//MCP4461 digiPot1(0x2c); //***A0 and A1 pins pulled low***

void setup(){

Wire.begin();        // join i2c bus (address optional for master)

//BEGIN TEST BLOCK IN Void Setup
//control byte
//Wire.beginTransmission(B00101111); // transmit to device (0x2f)// device address is specified in datasheet

Wire.beginTransmission(B00101101); //0x2c = (B00101100, 0x2d = B00101101, 0x2e = B00101110, 0x2f = 00101111
//command byte pot0
//Wire.write(B00000000);   //(0x00)pot0 voletile sends COMMAND instruction byte     
Wire.write(B00100001); //(0x02) pot0 non-voletile sends COMMAND instruction byte **have to POR for changes to take effect????? last bit is the first of the data byte below   
//data byte pot0
Wire.write(B00000000);       // sends potentiometer value byte 
//Wire.endTransmission();

//Wire.beginTransmission(0x2f);
//command byte pot1
//Wire.write(B00010000); //(0x01)pot1 voletile sends COMMAND instruction byte     
Wire.write(0x30); //(0x03) pot1 non-voletile sends COMMAND instruction byte **have to POR for changes to take effect????? last bit is the first of the data byte below   
//data byte pot1
Wire.write(B00000000);       // sends potentiometer value byte 
//Wire.endTransmission();

//Wire.beginTransmission(0x2f);
//command byte pot2
//Wire.write(B01100000);  //(0x06)pot2 voletile sends COMMAND instruction byte     
Wire.write(B10000001); //(0x08) pot2 non-voletile sends COMMAND instruction byte **have to POR for changes to take effect????? last bit is the first of the data byte below   
//data byte pot2
Wire.write(B00000000);       // sends potentiometer value byte 
//Wire.endTransmission();

//Wire.beginTransmission(0x2f);
//command byte pot3
//Wire.write(B01110000); //(0x07)pot3 voletile sends COMMAND instruction byte     
Wire.write(B10010001); //(0x09) pot3 non-voletile sends COMMAND instruction byte **have to POR for changes to take effect????? last bit is the first of the data byte below   
//data byte pot3
Wire.write(B00000000);       // sends potentiometer value byte 
Wire.endTransmission();     // stop transmitting

//END OF TEST BLOCK
}


void loop()
{
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.