Is there any Arduino Module that can do my job when interfaced with Uno?

the yellow colored bar indicates 0 level.

As in this picture iam transmitting a flashlight pulse which gets converted into voltage pulses of 2 levels (15v and 7v) and a 0 pulse (its pulse width is so low that it can be only visible when scaled down to us level). Both types of high pulses have different pulse widths. Now is there any arduino module that can step-down the 15v pulse as 5v and 7v pulse as 2.5 v and 0v pulse as 0? Or to be more general , it has to do 3 actions
1.) Step down any voltage > 10v to 5v
2.) Step down any voltage < 10v , but > 2v as 2.5 v
3.) Step down any voltage <2v as 0.

I need to give the stepped down output to A0 pin of arduino and will read the voltage using analogReadFast() . This is my requirement and arrangement , is there a solution ?

PS : I am sorry guys, as per my code any voltage less than 2 v would be automatically 0 as it is equivalent to a digital pin's off! , so just care about 2 levels, >10 v and <10 v

Stepping down voltage or providing directly power is usually not the role of an MCU - use a dedicated circuit for that (simple resistor divider, transistor, series of diodes, step down converters, voltage adaptors,…)

If timing matters I would look at a hardware construct with two or even three pins output at MCU voltage and connect to digital pins. A digital Reading of the port and masking will give you quickly one of the 3 state to deal with rather than go analogRead - even fast. (or using interrupts on MCU with At least 3 interrupts)

Two resistors to create a voltage divider, 2k2 and 1k will get you close, below uses 3 to get a more accurate 3:1 ratio.
Question is if you can accept 7.5V to be translated to 2.5V?

Your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advise on) your project :wink: See About the IDE 1.x category.

Can you elucidate a bit more, basically my logic goes like this:

  • Any pulse with a high time width >= 10 ms and a voltage level <10 v is a 0, else it is a 1 . So basically 1 and 0 differ in both voltage as well as high-time pulse width , i thought analogReadFast() is the only thing that can differentiate between these voltage levels , (coz digital pins just spit out whether its a high or low right?) It would be great If can you elucidate a bit more for me about how can get rid of the analogRead() and use interrupts in my case.

Iam attaching my arduino code here, if that's useful for you to help me out:

#include <avdweb_AnalogReadFast.h>
#define BUTTON_PIN 3
#define apin A0
const int t=200;
word pulseWidth[t];
word v[t];
volatile unsigned long pulseInTimeBegin = micros();
volatile unsigned long pulseInTimeEnd = micros();
volatile bool newPulseDurationAvailable = false;
 int a;
int c=0;
int f=0;
const float mvc=4.88;
 
void buttonPinInterrupt()
{
  if (digitalRead(BUTTON_PIN) == HIGH) {
    // start measuring
    pulseInTimeBegin = micros();
    if(f==0){                                               /*  while my digital pin is high i start measuring pulse width as well as voltage  using analogReadFast() , so for every pulsewidth data that i save in pulseWidth array , i have a voltage entry saved in V array  */

    v[c]=analogReadFast(apin);
    f=1;}
  }

  else {
    // stop measuring
    pulseInTimeEnd = micros();
    newPulseDurationAvailable = true;
   f=0;
  }
}

void setup() {
  for (int i = 0; i < t; i++) {
    pulseWidth[i] = 0; // clears the array
    v[i]=0;
  }
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT);

  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN),
                  buttonPinInterrupt,
                  CHANGE);
}

void loop() {
  if (newPulseDurationAvailable) {
    newPulseDurationAvailable = false;
    unsigned long pulseDuration = pulseInTimeEnd - pulseInTimeBegin;
    //Serial.println(pulseDuration);
    c+=1;
   
    pulseWidth[c-1] =pulseDuration ;
  
      
  }

   if (c==t-1) { // print 100 results
    for (int i = 0; i < t-1; i++) {
     
      
      if(pulseWidth[i]>=10000 and v[i]*mvc<10000){ // checking that if pulse width  >= 10 ms and voltage < 10V
        Serial.println(0);
       
        }
      else{
        Serial.println(1);
      }
      
    
    }
   for (int i = 0; i < t; i++) {
      //Serial.println(pulseWidth[i]);
      pulseWidth[i] = 0; // clears the array
      v[i]=0;
      c=0;
    }

  }

  
}

Sure , as i said anything less than 10 v and greater than 2v , i want them to be in the 2.5 v range , so i can definitely accept 7.5 v as 2.5 v !!!

@edmundkemper, please edit your post, select all code and click the </> button to apply so-called code tags and next save your post. It makes it easier to read, easier to copy and prevents the forum software from incorrect interpretation of the code.

Edited the post that contains my code, thank you for the tips @sterretje

1 Like

I don't think this can be done with resistors.

  1. would be V/2, analog threshold limited to 5V by voltage clamping
  2. would be the output of an analog threshold detector such as comparator
  3. would be the output of an analog threshold detector such as comparator

It's hard to treat your request at face value. The three values 0,2.5,5V look suspiciously like digital thresholds, and invite the question, Why and what are you doing with them? Frequently here, somewhat opaque requests like this one, conceal fundamentally flawed or overburdened approaches that require band-aid fixes. Once those are put aside, conventional design approaches often provide easy solutions. So it would greatly behoove you to explain more about source of the input voltage, and the use to which it will be put. In other words, sufficient context.

Otherwise you will get the solution to the solution of the problem, not the solution to the problem.

1 Like

I'd simply use the circuit which @sterretje drew in post #3 but with the cathode of a 15v Zener diode between R1 and R2 and its anode on GND.
The voltage delivered at A0 will be one third of the input voltage but capped at 5 volts so you can calculate the original voltage range and act accordingly. This applies if you are using a 5v Arduino such as a Uno.

> 10v             AR >= 675
< 10v , but > 2v  AR >= 137 && AR < 675 
<2v               AR < 137 

AR is AnalogRead() assuming 10bit ADC and 5V reference.

EDIT
Or better a 5v Zener across R3

Lacking the context I mentioned, if you have a 3-level signal and you want to sample it digitally, you can make a comparator circuit to convert the ranges to a digital output map (in this case two outputs).

The configuration of the comparator array would best be determined by which level state changes you are detecting, which require the timing that you need.

You didn't express exactly what those are, it might be obvious if we knew what you were up to, but if you can express those needs very clearly and in detail, it might be possible.

Example:
Comparator A is active when input > 10V (detects 15V pulse)
Comparator B is active when (7V > input > 2.5V)

If you said more about your application, I could also suggest making the comparator hardware simpler and sorting out the analog "bins" in software by performing simple logic on the pins (but may not satisfy a requirement for triggering an interrupt):
Example:
Comparator A is active when input > 10V (detects 15V pulse)
Comparator B is active when input > 2.5V

In this case it is still possible to differentiate all three states.

Each comparator output would go to a digital input pin, it can be interrupt enabled if you like, it all depends on what states/transitions you want to detect, and how you need to respond to them (timing).

The point of doing it this way, is that it has the fastest response capability, if speed is what you need. You said that your 0 pulse was "so low that it can be only visible when scaled down to us level". Throw us a bone. You could have just told us what it is.

You have to step down the voltages by using step down converters/voltage divider circuits. Then you have to connect it to the arduino's analog pins.

I think that was covered pretty well in post #3.

If you take the OP's request at face value, a voltage range between 2 and 2.5volts has to appear as 2.5 volts. Any attempt to do this using step down converters/voltage divider circuits will lead to certain disappointment.

1 Like

Hi, @edmundkemper
Can you please tell us the scope of your project?
What does it do, where are the flashes of light coming from and why?
Why are they three level, (include 0V)?

Even more importantly;
Can you please tell us your electronics, programming, arduino, hardware experience?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

Okay , you clearly mentioned you need the reason why iam doing this , so you could help me to possibly land on a easy solution, okay ! Iam sorry but this going to be a long one , but i will try to compress as much as possible and i will try my best!

poof! here goes:

Iam doing a Visible Light Communication project, where my smartphone (Redmi note 5 pro) Flashlight becomes the source. So i rooted my phone and wrote a shell script

binary sequence =[0,1,0,0,.......(blah blah , some binary sequence) .....]
for  in in binary sequence:
        if[i=0]:
         echo "0" > /sys/class/leds/flashlight/brightness   //turns off the flashlight
         sleep(0.001)  // delay of 1 ms
        else:
        echo "100" > /sys/class/leds/flashlight/brightness   //turns on the flashlight
        sleep(0.001)  // delay of 1ms

Expectation :
So a 0 is just 0v pulse and a 1 is a 5 v pulse , just sample at the reciever side at 1 ms and you are good to go.

Reality:
As a smartphone is a General Purpose OS based system, you can't expect any guarantees that too in the milli second level, what happened is the pulse width gets streched beyond the 1ms limit , thus the reciever gets its synchronization all wrong! for eg if you sent a 110 , the reciever would record a 1 pulse for 5 ms (due to OS delay , even if i programmed it to be on for 1 ms it gets to 5 ms) , another 1 for 10 ms and a 0 for 2 ms , and it would output as 11111 1111111111 00 , instead of 110!

The picture demonstrates this . Now how would you encode data reliably?

Solution:
Encoding 1s and 0s in the form of their high-time pulse width. A 1 is any pulse that has an on time of 10 ms or higher , else it is a 0 ( A zero pulse has an on time and an off time , it has got no programmed delay , practically a zero pulse has a 256 us (mean pulse width) on time and 256 us (mean) off time , whereas a one pulse has a 20 ms on time(mean) and 256 us (mean) off time. A code would do better for you

for  in in binary sequence:
        if[i=0]:
         echo "100" > /sys/class/leds/flashlight/brightness  
         echo "0" >/sys/class/leds/flashlight/brightness                               /* these two statements produce an on off pulse that has a mean on time of 256 us and mean off time of 256 us*/

        else:    // if i is 1
        echo "100" > /sys/class/leds/flashlight/brightness  
       sleep (0.01)                                                                                   // 10 ms delay
        echo "0" >/sys/class/leds/flashlight/brightness  /*   these two statements produce an on off pulse that has a mean on time of 20 ms  and mean off time of 256 us .*/

Pictorially this is how it looks! as i said earlier 1 and 0 both bit's symbol has a high time and low time, i only differentiate 1 and 0 based on their respective symbol 's high time(flashlight on) , i don't even care about their low time (flashlight off) as depicted in the picture .

Reality :
This solves my problem as i can clearly differentiate between a 1 whose high time is more than 10 ms , else it is a 0 .

Problem with this method :
One Word : LOW DATA RATE!!!!! , iam differentiating 1 and 0 in time and thus knowingly reduce my data rate , i need a data rate of at least 1 Khz, this shit's just 52 Hz!!! :face_with_symbols_over_mouth: One could go einstein and say , reduce the on-time delay for 1 to something around 5 ms and change the receiver algorithm to anything >= 5 ms as 1 else :0 , good one mr einstein, but in reality the 0 pulse on-time gets streched upto 7 or 8 ms!!! ,leading to bit error! that's why i fixed 10 ms as the threshold to seperate a 1 from a 0.

I thought, i want to increase my data rate , but if i reduce the delay for diffrentiating 1 from 0 i run a risk of bit error , now how do i solve this? :thinking:

A Light Bulb on the top of my Head:
Now you get caught when you only differentiate 1 and 0 based on pulse width, why dont you also differentiate them based on voltage so that even if pulse width fails, voltage hails! :smiley: sorry for the punch! Here is my code:

 for i  in binary sequence:
        if[i=0]:
         echo "1" > /sys/class/leds/flashlight/brightness     // a lower intensity flashlight produces a lower voltage
         echo "0" >/sys/class/leds/flashlight/brightness                               

        else:    // if i is 1
        echo "200" > /sys/class/leds/flashlight/brightness    // a higher intensity flashlight produces a higher voltage.
       sleep (0.005)                                                                                   // 5 ms delay yikes!
        echo "0" >/sys/class/leds/flashlight/brightness  

The image that i have attached in my very first post is the output except i added the 5 ms delay for 0 rather than 1 , nothing else .

Now my receiver checks if i receive a pulse it should satisfy 2 conditions to be a 1:

  1. It should have a delay >=5 ms
  2. It should have a voltage greater > 10V.

Now for a 0 pulse, it has a risk of having high time pulse widths greater than 5 ms, but it gets caught at the second condition and rightly gets identified as 0 , , provided condition 2. is always reliable!!

I have attached my receiver code (arduino code) in my previous post , there i have applied the conditions to 0 rather than 1 .

Expectation:

This is my story, i hope you can understand why i want this approach to work desperately.

PS: AGAIN, Sorry for the extremely long post and sorry for my funny tone!! :smiley: .

PS AGAIN ! : I am sorry guys, as per my code any voltage less than 2 v would be automatically 0 as it is equivalent to a digital pin's off! , so just care about 2 levels, >10 v and <10 v

@TomGeorge , please refer post #15 for why iam doing this.
Regarding your next question i just have a single answer :smiley:
Iam a noob, iam new to electronics and arduino , wrt programming i can say i have beem doing it since my 3rd year in my undergraduate!

I have a question, to add to the ones that you mostly answered. How did those voltage levels come into existence? If you are sending light from a phone to some light sensitive receiver, the received level will of course vary, as the distance and orientation of the phone varies. As you have self-identified as a noob to electronics, I'm curious how you handle that in the receiver. Any practical implementation of this scheme would have to. Why are voltages in excess of the Arduino 5V supply even in play? Why are they necessary?

I knew it would come to this question , i didn't include this in my previous post to shorten it. Now to answer this , i have to explain you about my receiver. My receiver is a very simple circuit with a photodiode array connected to pin 2 of a LM358 amp with pin 3 grounded . I gave a Vcc of 5v and pin no 4 to Gnd of my source/battery, and i typically observe an output voltage of 4 v under light and 11 mv without light. Also , as you said , distance of the transmitter from reciever is important , i typically keep it very close to the receiver as close such that my communication system can be basically classified as NFC , my reciever misses pulses if i keep my transmitter a little far away Under this condition, when i tried this code

I got the same voltage for echo "1" as well as echo "200" ! you could say , move your phone a little bit apart from the receiver , now the problem is my receiver misses pulses , it is that sensitive , that i really need to keep the transmitter very close to my reciever. Now one thing i observed was when i increase my Vcc to like 15 v , the difference between the voltage that echo "1" produces and echo "200" produces becomes obvious, i have even attached the picture in my very first post , that's the reason why i need a higher voltage , i cannot compromise on the distance , coz the reciever can miss pulses!

Hi,

Can I suggest you add on the output of the 358, a comparator to square up and refine the output to 0V to 5V.
This will make one job less in your code, doing it in hardware is simple and fast.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Then you either didn't read, or didn't comprehend the introductory threads that explain to newcomers, why you should include things like that at the very beginning. I can't recall a single case where anyone posted too much information.