Hi everyone, I am working on a project for my thesis and am having some difficulty programming the Arduino Atmega328p microcontroller to simulate a pulse oximeter. I am using two LEDs, one red and one infrared, and a photodiode in the A0 channel of the ADC to acquire the signal of the two different wavelengths. My goal is to convert these values and transmit them via the USART serial interface to the computer for plotting.
I am trying to program the microcontroller to cyclically turn the LEDs on and off, and acquire the signal only when one of the two LEDs is on for the duration of the period it remains on. I am new to Arduino programming and would like to get some advice on how to proceed.
Hi all, I am working on a project for my thesis and I am having some difficulty programming the Arduino Atmega328p microcontroller to simulate a pulse oximeter. I am using two LEDs, one red and one infrared, and a photodiode in the A0 channel of the ADC to acquire the signal of the two different wavelengths. My goal is to convert these values and transmit them via the USART serial interface to the computer for plotting.
I am trying to program the microcontroller to cyclically turn the LEDs on and off, and acquire the signal only when one of the two LEDs is on for the duration of the period it remains on. I am new to Arduino programming and would like to get some advice on how to proceed.
This code is designed to acquire photoplethysmographic signals via via two LEDs one for red light and one for infrared light using Arduino's ATMEGA328p microcontroller. The code should handle the on/off cycle of the LEDs and acquire the signal from the A0 channel of the ADC only when one of the two LEDs is on and for as long as the LED remains on.
During the LED on/off cycle, there are three phases. A variable 'Counter' is set, which is incremented to the desired value at each timer interrupt to select the duration of the entire cycle. In the first phase, the ambient light value is calculated when both LEDs are off. In the next two phases, alternately, the voltage values for red light and infrared light related to the turning on of the two LEDs are calculated. In this way, the cancellation of the ambient light is obtained by subtracting the voltage value of the ambient light from the voltage of the red and infrared light. Using a control variable "flag," the end of a cycle is established. The voltage values are then sent via Usart serial communication to the compiuter for plotting,but unfortunately it does not work.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#define BAUDRATE 9600
#define UCCR ((F_CPU / (BAUDRATE * 16UL)) - 1)
volatile uint8_t red_led = 0;
volatile uint8_t ir_led= 0;
volatile uint8_t red_adc = 0;
volatile uint8_t ir_adc= 0;
void USART_init(void) {
UBRR0H = (uint8_t)(UCCR >> 8);
UBRR0L = (uint8_t)(UCCR);
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (1<<UCSZO1)|(1<< UCSZ00);
}
void USART_send(unsigned char data) {
while(!(UCSR0A & (1 << UDRE0)));
UDR0 = data;
}
int adc_read(int ch) {
ADMUX = (ADMUX & 0xF8) | ch;
ADCSRA |= (1 << 6);
while(ADCSRA & (1 << 6));
return ADC;
}
ISR(TIMER1_COMPA_vect) {
static int counter = 0;
static int luceambientale = 0;
static int countercamp= 0;
static int campioni= 10;
static int flag = 0;
if (counter == 0) {
luceambientale = adc_read(0);
}
else if (counter == 1) {
PORTB = 0x01;
red_adc = 1;
red_led= 1;
}
else if (counter == 2) {
PORTB = 0x02;
ir_adc = 1;
ir_led = 1;
}
else if (counter == 3) {
PORTB = 0x00;
countercamp++;
if (countercamp == campioni) {
flag = 1;
countercamp = 0;
counter = 0;
}
}
counter++;
}
int main(void) {
unsigned char u=0, d=0, c=0, m=0;
int valorealross=0; valorerealir=0;
int valutered=0, valuterir=0;
DDRB = 0x03;
PORTB = 0x00;
OCR1AH= (unsigned) (40000>>8);
OCR1AL=(unsigned) (40000);
TCRR1A=0;
TCCR1B = (1 << WGM12) |(1 << CS11);
TCCR1C=0;
TIMSK1=(1<<OCIE1A);
USART_init();
ADMUX=(ADMUX&0X3F)|(1<<REFS0);
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
sei();
while(1) {
if (red_adc == 1) {
valorerealross = adc_read(0) - luceambientale;
red_adc= 0;
red_led = 0;
valutered= valorerealross;
m = valutered / 1000;
c = ( valutered- m * 1000) / 100;
d = (valutered - m * 1000 - c * 100) / 10;
u = valutered- m * 1000 - c* 100 - d * 10;
USART_send((unsigned char) (m + '0');
USART_send((unsigned char) c + '0');
USART_send((unsigned char) d + '0');
USART_send(((unsigned char) u + '0');
USART_send('\n');
}
if (ir_adc== 1) {
valorerealir = adc_read(0) - luceambientale;
ir_adc = 0;
ir_led= 0;
valuterir=valorerealir;
m = valuterir / 1000;
c = ( valuterir - m * 1000) / 100;
d = ( valuterir - m * 1000 - c * 100) / 10;
u = valuterir - m * 1000 - c * 100 - d * 10;
USART_send((unsigned char) m + '0');
USART_send((unsigned char) c + '0');
USART_send((unsigned char) d + '0');
USART_send((unsigned char) u + '0');
USART_send('\n');
}
if (flag == 1) {
flag = 0;
}
}
return 0;
I tested the program, but it does nothing.... it doesn't turn on the LEDs and consequently no acquisition is done. I don't understand what the error is in the program
I cannot use IDE ARDUINO with the various libraries, because I was told to implement the program, only through the microcontroller. I use the The SFH7072 photodiode is sensitive to electromagnetic radiation in the wavelength range of 400 to 1100 nanometers (nm).
The SFH7072 sensor uses two LEDs to transmit light at a specific wavelength, which depends on the type of LED used. According to the sensor datasheet, the red LED has a wavelength of about 660 nm, while the infrared LED has a wavelength of about 870 nm.
Would it be cheating to do as @gcjr suggests might actually be much easier, then spend time looking at the libraries you may have needed to use to see how to get things done down on the metal?
Get the hole thing working like you were any regular noob with an UNO and some time.
Did you at least get the UART stuff functioning in the absence of any complications around the timer/counter things you are trying for the sensing?
I thought of using interrupts to better manage the cycle of turning the LEDs on and off.
How do you recommend that I implement the code with the polling method? If I use the _delay_ms function to handle the cycle of turning the LEDs on and off, how can I then implement something that constantly checks the status of the LEDs so that I can see if one of the LEDs is on or off. Only when one of the LEDs is on, can you capture the signal for as long as the LED remains on.
No, unfortunately no. this program does not work. The LEDs do not light and therefore no acquisition is made as written in the main loop. Since there is no acquisition nothing is sent to the serial interface
look over the following
not really sure what you're trying to do but following demonstrates sequencing LEDs on/off, monitoring and reporting cnts in each state
// monitor two LEDs with photo diode
const byte PinPhoto = A0;
const byte PinLedRed = 11;
const byte PinLedIr = 12;
enum { Off = HIGH, On = LOW };
const int Margin = 10;
int avgAmbient;
unsigned long cnt;
const unsigned long MsecPeriod = 500;
unsigned long msecLst;
char s [80];
int state;
// -----------------------------------------------------------------------------
void loop ()
{
// cycle thru each LED state every 500 msec
unsigned long msec = millis ();
if (msec - msecLst >= MsecPeriod) {
msecLst = msec;
// report state cnts in each state
sprintf (s, "%s: state %d cnts %6ld",
__func__, state, cnt);
Serial.println (s);
cnt = 0;
// sequence thru LED states
switch (state) {
case 0: // both LEDs off
digitalWrite (PinLedRed, Off);
digitalWrite (PinLedIr, Off);
state = 1;
break;
case 1: // Red LEDs on
digitalWrite (PinLedRed, On);
digitalWrite (PinLedIr, Off);
state = 2;
break;
case 2: // IR LEDs on
digitalWrite (PinLedRed, Off);
digitalWrite (PinLedIr, On);
state = 0;
break;
}
}
// increment cnt when photo diode reading exceeds ambient
if ((avgAmbient + Margin) < analogRead (PinPhoto))
cnt++;
delay (1000);
}
// -----------------------------------------------------------------------------
// return average analog measurement with specified LED active
int
measure (
byte pinLed,
int nSamp )
{
if (pinLed)
digitalWrite (pinLed, On);
unsigned long sum;
for (int n = 0; n < nSamp; n++)
sum += analogRead (PinPhoto);
if (pinLed)
digitalWrite (pinLed, Off);
int avg = sum / nSamp;
sprintf (s, "%s: %2d %6d %6ld %6d", __func__, pinLed, avg, sum, nSamp);
Serial.println (s);
return avg;
}
// -----------------------------------------------------------------------------
void
setup ()
{
Serial.begin (9600);
Serial.println ("Photoplethysmographic Signals");
digitalWrite (PinLedRed, Off);
digitalWrite (PinLedIr, Off);
pinMode (PinLedRed, OUTPUT);
pinMode (PinLedIr, OUTPUT);
avgAmbient = measure (0, 100);
}
i assume controlling the LEDs and making analog measurements is not difficult without the Arduino IDE, but some serial infrastructure would be needed to format and buffer serial output
i'm trying to make you understand that you could separate the variuos issues you are strukkling with.
Write a program that does nothing but use the UART to transmit "hello world!".
If receiving is at all important, write a program that does nothing but turn on an LED when it hears a particular message, or even a particular character.
In the same fashion write a program that gives any indication that your sensors are working, like an LED or two or three that would light up at various ranges.
Do you have access to an oscilloscope or logic analyser?
Getting something like this going in the way you seem to be trying isn't something even the most experience or expert would do.
I suggest again to you to use an UNO, use the IDE, use the libraries and get some good feel for how the sensking is working, or not working.
Since you seem to be alone in the woods on this, there is no shame in delving into Arduino libraries to see how things work, how they are made to function when dealing directly with the i/o ports or pins and the peripherals available on the processor.
I see now you've marked your own post as the solution, so does that mean you've solved this and we can forget about you move on?