The adc function on attiny44 not working as needed? - arduino

enter image description hereI have been fighting alot to get this thing work but unfortunately, it is not working as needed. The sensor is extremely sensitive under little light it detect high, it has to be pitch dark in order to read low signal. Please let me know where am i wrong. I have directly connected solar panel to PA1 of ATTINY44 IC.
NOTE: Currently, I am not using any resistor with Attiny44A.
solar panel V=5V; Current=30mA.
Battery voltage = 3.7~4.2V, 1200mAH.
Here's my schematic
I don't believe that there is any power issue because i tried executing same code with 5v Arduino supply. Even if tiny bit of light falls onto it, the led turns ON.
I dont want it to be extremely sensitive
#include <avr/io.h>
int led =0;
bool Stop=false;
//int solar = 3;
void setup() {
pinMode (led, OUTPUT);
//pinMode (solar, INPUT);
ADMUX =
(1 << REFS1) | // Sets ref. voltage to Vcc, bit 1
(0 << REFS0) | // Sets ref. voltage to Vcc, bit 0 //internal 1.1v voltage reference
(0 << MUX5) | // use ADC1 for input (PA1), MUX bit 5
(0 << MUX4) | // use ADC1 for input (PA1), MUX bit 4
(0 << MUX3) | // use ADC1 for input (PA1), MUX bit 3
(0 << MUX2) | // use ADC1 for input (PA1), MUX bit 2
(0 << MUX1) | // use ADC1 for input (PA1), MUX bit 1
(1 << MUX0); // use ADC1 for input (PA1), MUX bit 0
ADCSRA =
(1 << ADEN) | // Enable ADC
(1 << ADPS2) | // set prescaler to 16, bit 2
(0 << ADPS1) | // set prescaler to 16, bit 1
(0 << ADPS0); // set prescaler to 16, bit 0
ADCSRB =
(1 << ADLAR); // left shift result (for 8-bit values)
// (0 << ADLAR); // right shift result (for 10-bit values)
}
void loop() {
ADCSRA |= (1 << ADSC); // start ADC measurement
while (ADCSRA & (1 << ADSC) ); // wait till conversion complete
//ADCH = (solar);
if (ADCH >= 128)
{
digitalWrite(led,HIGH);
//Stop=true;
}
else
{
// Stop=false;
digitalWrite (led, LOW);
// ADC input voltage is less than half of VCC
}
return 0;
}
This is my code for your reference.

Related

WHy is this code not executing (ADC BATTERY VOLTAGE MEASURE)

EDIT NEW PICTURE
void setup() {
Serial.begin(9600);
Serial.println("Setup completed.");
}
void loop() {
// Read external battery VCC voltage
Serial.print("Bat: ");
uint16_t batVolts = getBatteryVolts();
Serial.print(batVolts);
Serial.print(" - ");
Serial.println(getBatteryVolts2());
delay(500);
}
// One way of getting the battery voltate without any double or float calculations
unsigned int getBatteryVolts() {
//http://www.gammon.com.au/adc
// Adjust this value to your boards specific internal BG voltage x1000
const long InternalReferenceVoltage = 1100L; // <-- change this for your ATMEga328P pin 21 AREF value
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference
// MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) -Selects channel 14, bandgap voltage, to measure
ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
// Let mux settle a little to get a more stable A/D conversion
delay(50);
// Start a conversion
ADCSRA |= _BV( ADSC );
// Wait for conversion to complete
while ( ( (ADCSRA & (1 << ADSC)) != 0 ) );
// Scale the value - calculates for straight line value
unsigned int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L;
return results;
}
// A different way using float to determine the VCC voltage
float getBatteryVolts2() {
// You MUST measure the voltage at pin 21 (AREF) using just a simple one line sketch consisting
// of: analogReference(INTERNAL);
// analogRead(A0);
// Then use the measured value here.
const float InternalReferenceVoltage = 1.1; // <- as measured (or 1v1 by default)
// turn ADC on
ADCSRA = bit (ADEN);
// Prescaler of 128
ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2);
// MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) - Selects channel 14, bandgap voltage, to measure
ADMUX = bit (REFS0) ;
ADMUX |= B00000000; //I made it A0 //ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
// let it stabilize
delay (10);
// start a conversion
bitSet (ADCSRA, ADSC);
// Wait for the conversion to finish
while (bit_is_set(ADCSRA, ADSC))
{
;
}
// Float normally reduces precion but works OK here. Add 0.5 for rounding not truncating.
float results = InternalReferenceVoltage / float (ADC + 0.5) * 1024.0;
return results;
}
I tried executing this program but it did not work i believe there is some issue with my pin declaration or circuit. Please check. I want the code to read my voltage but it constantly reads wrong value and it is not even reading from A0
enter image description here
I just changed this part of the code
enter image description here
Unfortunately you did not follow my advice to study the linked information at https://github.com/RalphBacon/Arduino-Battery-Monitor. Especially those provided at http://www.gammon.com.au/adc
Instead you obviously messed with the first snipped you found without understanding what it does.
Otherwise I cannot explain why you would change
ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
to
ADMUX = bit (REFS0) ;
ADMUX |= B00000000;
You don't want to read analog channel 0. You want to read the bandgap voltage (which is used as internal reference voltage).
There's the reference voltage, the ADC value and the measured voltage.
Usually you would use a known reference voltage and the ADC value to calculate the measured voltage.
V = ADC * Aref / 1023
But in this case you use the ADC voltage and the known measured voltage to calculate the reference voltage, which is the voltage of your battery connected to Aref.
Aref = V_bandgap * 1023 / ADC
But in order to do that you must set the ADMUX register to measure the internal voltage reference (1.1V) using an external reference voltage.

ESP32 ADXL345 doesn't get the negative values

Hi I can run this code without any problem on Arduino UNO. My output is like : 0.05 0.10 1.01
But when I run this code on ESP32, my output is : 255.89 255.81 0.99 and I don't see any minus value. What is the problem?
ESP32's X,Y,Z raw values like : 6500 0 , 65000 , 1 . ESP32 can't get the negative values. I have to do something with wire.h and I need to change uint8_t or uint16_t something but I really don't understand how should I solve this problem.
#include <Wire.h> // Wire library - used for I2C communication
int ADXL345 = 0x53; // The ADXL345 sensor I2C address
float X_out, Y_out, Z_out; // Outputs
float X, Y, Z ;
void setup() {
Serial.begin(115200); // Initiate serial communication for printing the results on the Serial monitor
Wire.begin(); // Initiate the Wire library
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x31);
Wire.write(0x0B);
Wire.endTransmission();
Wire.beginTransmission(ADXL345);
Wire.write(0x20); // Z-axis offset register
Wire.write(-7);
Wire.endTransmission();
Wire.beginTransmission(ADXL345);
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(0x08); // (8dec -> 0000 1000 binary) Bit D3 High for measuring enable
Wire.endTransmission();
Wire.beginTransmission(ADXL345);
Wire.write(0x2C);
// Enable measurement
Wire.write(0x09); //For low power 000x x pin set to 1 /1001 determine Hz
Wire.endTransmission();
delay(10);
}
void loop() {
unsigned long Time = millis();
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read() | Wire.read() << 8); // X-axis value
X = X_out /256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read() | Wire.read() << 8); // Y-axis value
Y = Y_out /256;
Z_out = ( Wire.read() | Wire.read() << 8); // Z-axis value
Z = Z_out /256;
delay(20);
Serial.print(X);
Serial.print(" ");
Serial.print(Y);
Serial.print(" ");
Serial.print(Z);
Serial.println(" ");
}
On the Arduino Uno there are 16-bit integers. The ADXL345 seems to receive this data format. Therefore everything plays out nicely. You are using 32-bit integers on the ESP32. Therefore you have to choose the right data type explicitly. Otherwise the negative numbers appear in the positive region.
The execution order of the Wire.read()-calls is not defined in your code. Therefore the compiler may join the bytes 0xAA and 0xBB to 0xAABB or 0xBBAA. You should add a sequence point to make sure that the code does what's intended.
I have not tested this code. That should be the correct order, in case I got the datasheet description right:
int16_t readInt16()
{
int lsb = Wire.read();
int msb = Wire.read();
return int16_t(lsb | msb << 8);
}
X_out = readInt16() / 256.f;
Y_out = readInt16() / 256.f;
Z_out = readInt16() / 256.f;

How do I output a compare match to OC1B in Fast PWM mode on the ATtiny84?

My goal is to output a PWM signal from my ATtiny84 with 1ms high at 50hz. The clock is operating at 1mhz, so I've set the compare output mode such that the output pin should be cleared for 19000 clock ticks and be set for 1000.
The device is powered at 5V and I have an oscilloscope reading a flat 5V output from pin A5 (OC1B), no modulation. My code is here:
#include <avr\io.h>
void init_pwm_generator()
{
PORTA &= ~(1 << (PORTA5));
ICR1 = 20000;
TCCR1A = (1<<COM1B1) | (1<COM1B0) | (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
}
int main(void)
{
DDRA |= (1 << (DDA5));
init_pwm_generator();
while(1)
{
OCR1B = ICR1 - 1000;
}
}
I can't figure out why this isn't working!
See the datasheet chapter 12.5 Input Capture Unit at page 91
The ICR1 Register can only be written when using a Waveform Generation mode that utilizesthe ICR1 Register for defining the counter’s TOP value. In these cases the Waveform Genera-tion mode (WGM13:0) bits must be set before the TOP value can be written to the ICR1Register.
So, correct initialization sequence will be as follows:
// Init the timer
TCCR1A = (1<<COM1B1) | (1<COM1B0) | (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12);
ICR1 = 19999; // set the top value
OCR1B = 19000; // set compare match value
TCCR1B |= (1<<CS10); // start the timer
Please note, for the timer period to be 20000 ticks you have to set TOP value to 19999 (since the timer counts from zero)

why adc always reads 1023 irrespective of input

I am trying to read a analogue voltage using the ADC in attiny85. But the ADC register always read 1023 irrespective of what input is given.
Moreover when the ADC pin is measured with a multimeter it shows nearly 3.1V. I aasumed that it is pulled up but the fact is, when i connect the pin to its analog input , the voltage at the pin disturbs the input voltage circuit. I dont know why this happens. the same code worked well before 6 months but now it is not. reason unknown. could anyone explain me what I'm actually doing wrong? I am using USBasp as my programmer and attiny85 as my target microcontroller, arduino as my compiler. Also i tried compiling using WinAVR but still the analogue input pin is at a voltage near 3.1V.
thanks in advance:)
#define F_CPU 16000000UL
#define myTx PB1 //PB1
#define myRx PB0 //PB0
#define ADC_CH_2 PB4
#define ADC_CH_3 PB3
#include <SoftwareSerial.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
float ADCval;
int i = 0, p;
SoftwareSerial myPort(myRx, myTx); //rx,tx
ISR(ADC_vect) {
p = ADCW;
ADCval = (float)p * 5.00f / 1024.0f;
//logging the data
myPort.print(i++);
myPort.print(" ADC: ");
myPort.print(p);
myPort.print(" voltage: ");
myPort.println(ADCval);
}
int main(void) {
myPort.begin(9600);
MCUCR &= ~(1 << PUD); //disabling Pull Up Disable i.e, enabling pullups
//I/O configuration
DDRB &= ~(1 << ADC_CH_2) & ~(1 << ADC_CH_3); //configuring as input
PORTB |= (1 << ADC_CH_2) | (1 << ADC_CH_3); // writing 1 to an input pin activates pullup-resistor
DIDR0 |= (1 << ADC_CH_2) | (1 << ADC_CH_3); // disable digital buffer
myPort.print("DDRB: ");
myPort.println(DDRB);
myPort.print("PORTB: ");
myPort.println(PORTB);
//ADC configuration
ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADIE); //enable conversion complete interrupt
ADCSRA |= (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2); // prescaler 128 - 16000000/128=125khz;
myPort.print("ADCSRA: ");
myPort.println(ADCSRA);
ADMUX &= ~(1 << ADLAR); // right most shift in ADCH and ADCL i.e, ADCH has two MSB bits and ADCL has 8 LSB bits
ADMUX |= (1 << REFS1) | (1 << REFS2); ADMUX &= ~(1 << REFS0); //Vref as 2.56V
ADMUX |= (1 << MUX1) | (1 << MUX0) ; ADMUX &= ~(1 << MUX2) & ~(1 << MUX3); //adc3
sei(); // enable all interrupts
myPort.print("ADMUX: ");
myPort.println(ADMUX);
while (1)
{
_delay_ms(1000);
ADCSRA |= 1 << ADSC;
myPort.print("DDRB: ");
myPort.println(DDRB);
myPort.print("ADMUX: ");
myPort.println(ADMUX);
myPort.print("ADCSRA: ");
myPort.println(ADCSRA);
myPort.print("PORTB: ");
myPort.println(PORTB);
}
return 0;
}
Update
the following image describes my output of different ADC channels for the same input voltage.
output of ADC channel 2
output of ADC channel 3
When the ADC configured with 2.56V as a reference voltage then all voltages at level 2.56 and above will be read as ADC's maximum value, i.e. 1023.
The same goes for 3.1 V.
Probably the issue is in the enabled internal pull-up:
PORTB |= (1 << ADC_CH_2) | (1 << ADC_CH_3); // writing 1 to an input pin activates pullup-resistor
Enabled pull-up will source additional current and change the voltage at the input. You should never use internal pull-ups with ADC since the pull-up's value is different from part to part in range 20k...50k, and it is hard to predict exact value.
You should disable it:
PORTB &= ~(1 << ADC_CH_2) & ~(1 << ADC_CH_3); // disable pull-ups
Use external pull-up of the known value, if needed.

Atmega 2560 USART not giving correct value on terminal

I am working on the serial communication of my MultiWii Pro board, which is based on a atmega2560. I am using avr-gcc to compile and avrdude to program.
Here is my problem. I am trying to get atmega2560 to send something (hex value) to the terminal. However, regardless of the value assigned to UDR2 and regardless the value I assigned to UBRR2L and UBRR2H, the terminal output is always 0xff if I set the terminal baud-rate at 9600, and 0xff if I set the terminal baud-rate at 115200.
Here is my code
#define F_CPU 8000000UL
#define BAUDRATE 19200 //The baudrate to use
#define BAUD_PRESCALLER ((F_CPU / (BAUDRATE * 16UL))-1)
static void InitializeUART()
{
UBRR2L = (uint8_t)(BAUD_PRESCALLER);
UBRR2H = (uint8_t)(BAUD_PRESCALLER>>8);
UCSR2B |= (1<<RXEN2) | (1<<TXEN2); //RX TX Enable
UCSR2C |= (1<<USBS2)|(1<<UCSZ21)|(1<<UCSZ20);
}
And my sending function
void USART2Write(char data)
{
while( !(UCSR2A & (1<<UDRE2)));
UCSR2B &= ~(1<<TXB82); //in the case if there are more than 8 bits of data
if(data & 0x100)
{
UCSR2B |= (1 << TXB82);
}
UDR2 = data;
}
In my case, the baudrate of my code is 19200. The terminal baudrate is also 19200. No matter what I assigned to UDR2, the output will always be 0x15.
Here is my fuse setting
Low High Extended
0xFF 0xD8 0xFD
UCSR2C |= (1<<USBS2)|(1<<UCSZ21)|(1<<UCSZ20);
USBS2 sets 2 stop bits. Is this intentional?
void USART2Write(char data){
while( !(UCSR2A & (1<<UDRE2)));
UCSR2B &= ~(1<<TXB82); //in the case if there are more than 8 bits of data
if(data & 0x100) {
UCSR2B |= (1 << TXB82);
}
UDR2 = data;
}
If you really want to use 9 data bits, UCSZ22, UCSZ21 and UCSZ20 have to be set. YOu only set UCSZ21 and UCSZ20
UCSR2C |= (1<<USBS2) | (1<<UCSZ21) | (1<<UCSZ20);
so I guess that USBS2 is indeed not what you want here. Maybe you were confused because the flag UCSZ22 is in the UCSR2B register.
So assuming you want 9 data bits and one stop bit use something like this:
static void InitializeUART() {
UBRR2L = (uint8_t)(BAUD_PRESCALLER);
UBRR2H = (uint8_t)(BAUD_PRESCALLER>>8);
UCSR2B |= (1 << RXEN2) | (1 << TXEN2) | (1 << UCSZ22);
UCSR2C |= (1 << UCSZ21) | (1 << UCSZ20);
}
Another thing: Your variable data is of type char and char is normally 8 bit wide. So the condition if(data & 0x100) is never satisfied.

Resources