Attiny13 Clock frequency and ADC - microcontroller

I am working with an Attiny13 AVR, which is programmed by arduino UNO over SPI.
I found a core for attiny13 and the content of the boards.txt file as follows;
#attiny13.name=Attiny13 # 128 KHz (internal watchdog oscillator)
#attiny13.upload.using=arduino:arduinoisp
# attiny13.upload.protocol=avrispv2
# attiny2313at1.upload.using=pololu
#attiny13.upload.maximum_size=1024
#attiny13.upload.speed=250 # important for not losing connection to a slow processor
#attiny13.bootloader.low_fuses=0x7B
#attiny13.bootloader.high_fuses=0xFF
#attiny13.bootloader.unlock_bits=0x3F
#attiny13.bootloader.lock_bits=0x3F
#attiny13.build.mcu=attiny13
#attiny13.build.f_cpu=128000
#attiny13.build.core=core13
########################
attiny13e.name=Attiny 13A standalone 9.6Mhz
attiny13e.upload.using=arduino:arduinoisp
attiny13e.upload.maximum_size=1024
attiny13e.upload.speed=19200
attiny13e.maximum_data_size=64
attiny13e.bootloader.low_fuses=0x7A
attiny13e.bootloader.high_fuses=0xFF
attiny13e.bootloader.path=empty
attiny13e.bootloader.file=empty
attiny13e.bootloader.unlock_bits=0xFF
attiny13e.bootloader.lock_bits=0xFF
attiny13e.build.mcu=attiny13
attiny13e.upload.tool=avrdude
attiny13e.build.f_cpu=9600000L
attiny13e.build.core=core13
When I am programming the attiny13, I select the "Attiny 13A standalone 9.6Mhz" as target board.
So, I expect it to run at 9.6Mhz.
I set the TCCR0B register as follows to get "No prescaling"
TCCR0B |= _BV(CS00);
TCCR0B &= ~_BV(CS01);
TCCR0B &= ~_BV(CS02);
Also set the PWM mode as "Fast PWM" by changing the TCCR0A register.
TCCR0A |= _BV(WGM00);
TCCR0A |= _BV(WGM01);
TCCR0A &= ~_BV(WGM02);
With those settings I should get 9.6Mhz/256 = 37.5 Khz PWM frequency. However, when I connect the output of the PWM to a MOSFET for driving and LED strip, I get and audible buzzing from the MOSFET.
That prompt me to think that my clock is not running at 9.6Mhz, since 37.5Khz is not an audible frequency.
So, I did another quick search on the topic of clock frequency and found the following webpage;
https://www.avrprogrammers.com/howto/sysclk-prescaler
If I didnt get it wrong, this page says that my clock frequency is divided by 8 by default.
To be able to get no divisor, I need to reset all the bits.
I did so and reseted all the CLKPS bits.
CLKPR = (1<<CLKPCE);
CLKPR = (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
So, in theory, I should get 9.6Mhz clock frequency with the divisor of 1.
When I use all those aforementioned settings, I no more hear a buzzing sound.
However, another problem emerged this time.
I use a potentiometer for controlling the brightness. When set the clock divisor to "1", behaviour of the potentiometer changed. Analog input does not read a value right away when I turned the potentiometer, so I need to turn it a little more to get the minimum brightness and it reaches to maximum brightness before I reach to other end of the potentiometer. So, I believe there is something wrong with the ADC.
Under the Analog to Digital Converter title I found the following information;
By default, the successive approximation circuitry requires an input
clock frequency between 50 kHz and 200 kHz to get maximum resolution.
If a lower resolution than 10 bits is needed, the input clock
frequency to the ADC can be higher than 200 kHz to get a higher sample
rate.
So, my clock frequency is 9.6Mhz and I need to set a prescaler in between 9.6Mhz/20Khz= 48 and 9.6Mhz/50Khz = 192 for the ADCSRA register.
I selected the division factor of 128, which requires setting all three bits ADPS2, ADPS1 and ADPS0.
ADCSRA != 1<< ADPS2;
ADCSRA != 1<< ADPS1;
ADCSRA != 1<< ADPS0;
This should set all three bits and keep the frequency of the ADC in between 50Khz - 200Khz.
However, I still get the same behaviour from the potentiometer.
Where am I wrong?

ADCSRA != 1<< ADPS2;
ADCSRA != 1<< ADPS1;
ADCSRA != 1<< ADPS0;
are three empty statements that have no effect. (They each retrun a boolean result.) Did you mean to write
ADCSRA |= 1<< ADPS2;
ADCSRA |= 1<< ADPS1;
ADCSRA |= 1<< ADPS0;
or
ADCSRA |= 1<< ADPS2 | 1<< ADPS1 | 1<< ADPS0;

Related

Why is the data coming out weird in arduino code?

I want to get data from the sensor(I used velostat). And this is my code.
Arduino Code
#define numRows 1
#define numCols 1
int rows_out = 13;
int cols_in = 12;
int Values = 0;
void setup() {
// set all rows and columns to INPUT (high impedance):
pinMode(rows_out, INPUT_PULLUP);
pinMode(cols_in, INPUT);
Serial.begin(9600);
}
void loop() {
pinMode(cols_in, OUTPUT); // set as OUTPUT
digitalWrite(cols_in, LOW); // set LOW
Values = analogRead(rows_out); // read INPUT
pinMode(cols_in, INPUT); // set back to INPUT!
// Print the incoming values of the grid:
Serial.println(Values);
delay(1000);
}
I made a sensor with velostat. It has two cable.
I connected one of them with an analog pin of arduino board. And the other one with GND and other analog pin. like this.
velostat cable 1 - analog pin 12
velostat cable 2 - analog pin 13 - GND
But when I upload this program, weird data is coming out on serial monitor.
Data displayed on serial monitor
4095
4095
4075
3283
3082
3056
2973
2941
2865
2685
2308
1859
1365
If anyone knows the reason, please help me. I guess it is because connection of cable has problem or I connected wrong pin, but i'm not sure.
The data could be fine, you most possibly skipped the calibration step.
A velostat measures pressure, but depending on the materials used to make the sensor, its PressureIn-VoltageOut characteristic may differ greatly. Furthermore, differences exist even in sensors with the same build, thus the need for calibration is vital in applications that require precision.
I would suggest you assume a linear characteristic for simplicity's sake, and do the following 3-step calibration:
Average out 10 values for when there's nothing pressing on the sensor. That'd be your zero reference. We'll reference it as X1.
Press with the average expected pressure on the velostat and average 10 measurements again. That'd be your 'ON' reference, and we'll reference it as X2. This ON value needs an arbitrary numeric equivalent. I chose 15.
In math, it'd look like:
aX1 + b = 0
aX2 + b = 15
Once you solve for a and b, your true values would be represented by: a*[measuerement]+b.
P.S.: Sorry for the horrendous math formatting, still not familiar how to integrate math nicely in markdown.
Later edit: Higher precision can be achieved by averaging across more measurements AND picking a larger arbitrary value for the second equation (to have more granularity).

ATTiny85 PWM frequency

I'm trying to use the ATTiny85 to control a bunch of LEDs. The LEDs have to be run at around 2Khz ( this is so that it doesn't flicker when being filmed). How would I change the frequency of PWM signals?
You can change it by setting different prescaler.
For Timer/Counter0 are available prescaler values: 1/8/64/256/1024.
So if you have 8MHz clock, and full 8bits PWM resolution you'll get: 31.25kHz / 3.9kHz / 448.28Hz / 122Hz / 30.5Hz
For Timer/Counter1 are available prescaler settings: 1 / 2 / 4 / 8 / 16 / ... / 16384. And it can be sourced by internal PLL clock (32MHz/64MHz).
So you can have prescaler set to divide source clock by 16 and at 8MHz clock it'll be 1953.125Hz.
With PLL Clock 32MHz division by 64 is needed and for 64MHz it's 128. But using PLL Clock is not needed for such small output frequencies.
I am not too familiar with this microcontroller, but from the documentation, it seems that you would like to configure the TCCR0B register (bits 2:0, refer to pages 79-80).
There, you can select a different prescaler, or no prescaler at all.

Simultanously Reading Two Analog Inputs with Arduino

We are simulating an oven. The potentiometer sets the desired temp and the sensor reads the current temperature of a little copper plate that is "the oven."
Both the temp sensor are connected to their own analog input pin on my arduino uno. Individually, I have gotten values for both the potentiometer and the temp sensor that make sense (I am monitoring the values on the serial window). However, when I adjust the potentiometer it significantly alters the sensor reading.
For example:
The potentiometer is at its 0 position, and the sensor is in the room temperature air. The serial shows TempSensor = 22 C, TSet = 0 C. This is normal.
Then when I turn the pot up: TempSensor= 40 C, TSet=55 C. -But the temperature sensor is still in the room temp air! So the pot value, TSet, goes up like it should, but also affects the sensor reading even though the temperature hasn't really changed.
Any advice would be greatly appreciated. Thanks!
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A3);
float tsens = map(sensorValue, 0, 1023, 0, 500);
int sensorValue2 = analogRead(A1);
float tset = map(sensorValue2, 0, 1023, 0, 70);
Serial.println(tsens);
Serial.println(tset);
}
I've recently bumped into a similar problem and my searches suggest that inserting a delay between the reads can help. On this question, I found this answer and this answer particularly helpful.
The idea is that you need to let some time pass after making a reading, then make another reading after the ADC has stabilized. Here's a function I have been using:
int safeAnalogRead(int pin)
{
int x = analogRead(pin); // make an initial reading to set up the ADC
delay(10); // let the ADC stabilize
x = analogRead(pin); // toss the first reading and take one we will keep
delay(10); // delay again to be friendly to future readings
return x;
}
I'm still having trouble getting an accurate reading of several potentiometers connected to the analog pins configured as a voltage dividers between vcc and ground, but at least now the values are stable.
BTW, it could be argued that since you have a delay after the first reading, it isn't necessary to have the second delay. This might matter if you call safeAnalogRead() twice in quick succession on two different pins.
You most likely have a ungrounded or miswired grounding on your temperature sensor. The pin configurations on the analog pins in Arduinos are layed out very close to each other such that floating voltages will move up or down when nearby pins have an applied voltage. If your ground connection (or power, though if it's correct at the beginning it's probably ground) for the sensor is disconnected or fixed to a high impedance line the analog voltages will move all over the place as other normally minuscule voltage sources will dominate the signal pathing. It probably fluctuates heavily if you put your finger near the A3 pin as well.
Is it noise or a bad value? I did a little test routine that looks at a pin and checks it against previous max and min values. I printed it to the serial monitor whenever a new boundary value showed up. If the wrong value is stable, check the circuit. If its noisey around a valid value, a digital low pass filter works pretty well. Take 34 readings of the pot. Find the highest and lowest values and discard those. Then take the average of the remaining 32 readings. I saw a 90% improvement in my setup (40 count error down to 3). 36 readings with 2 high and 2 low discarded would probably improve things further. If you have the time, you can do a double pass filter. Do this same process 34 times, then throw away the high and low and average it again. All together this is 34 x 34 readings, so noise should go away, but you are taking a long time to get a sample and a pot change will take awhile to get detected. To help with the time, I read the pot every pass through the main loop and save each value in a circular buffer. When I need to read a pot, I look at the historical 33 readings along with a 34th new one.
I have run into this issue before when reading multiple analog sensors in rapid succession. One possible cause(and the one I experienced) is the fact that the arduino only has 1 ADC and it charges a capacitor to take that reading. That capacitor can remain charged between readings thus skewing them.
Introducing a delay could potentially help with this as another user has pointed out, however the cleanest solution I was able to come up with was to "Reset" and discharge the ADC capacitor by taking an analog read of a third pin that is connected directly to ground.
int sensorValue;
int sensorValue2;
float tsens;
float tset;
int resetADC;
void setup()
{
Serial.begin(9600);
pinMode(A0,input);
pinMode(A1,input);
pinMode(A3,input);
}
void loop()
{
resetADC = analogRead(A0);
sensorValue = analogRead(A3);
tsens = map(sensorValue, 0, 1023, 0, 500);
resetADC = analogRead(A0);
sensorValue2 = analogRead(A1);
tset = map(sensorValue2, 0, 1023, 0, 70);
Serial.println(tsens);
Serial.println(tset);
}

I need help reading analog voltages in an arduino mega2560

I'm new to microcontrollers and I need help reading voltages and printing them in the serial monitor. I have done this using a potentiometer, but I was wondering if I could do the same with just voltages. Below is the code that I used when I read the potentiometer values:
I have tried reading voltages but when I input a voltage smaller than between 3-5V in pin A0 I get 0s in the serial monitor
int potPin = 0; // select the input pin
int val = 0; // variable to store the value coming from the function generator
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
val = analogRead(potPin); // read the value from the function generator
Serial.println(val);
delay(1000); //Sampling rate for the signal
}
as Udo Klein said, this looks like a hardware issue. try setting up your circuit like this: http://imgur.com/PYbeqLq
note that the grounds are shared between the function generator and the arduino - this is important for ensuring that voltages are measured correctly. remember that voltage is actually a difference in electric potential, so you need a common reference point to measure from.
To answer your question, yes you can read voltages from another piece of hardware.
As gearbot tells you it is important to keep a common ground between the arduino and the other piece of hardware.
Also be carefull, the arduino can only measure voltages between 0 and 5 Volts. Don't try to measure higher voltages without adjusting the circuitry as you might destroy your arduino board.
If you're unsure measure the voltages before attaching to the arduino with a multimeter.
The Uno has 6 analog inputs, labeled A0 through A5, each of which provide 10 bits of resolution (i.e. 1024 different values). By default they measure from ground to 5 volts, though is it possible to change the upper end of their range using the AREF pin and the analogReference() function.
edit:
I didn't see the added comment at the bottom of your post. This indicates indeed a hardware problem (probably in your circuitry)
To be sure the arduino does the right thing, measure the voltage with your multimeter between pin A0 and GND while your hardware is attached and working. You should be able to read the correct voltage there.
I suspect it will give the same values as the Arduino.
Then trace back your circuitry with your multimeter (keeping GND attached) to find where something is going wrong.
Try scaling your 0 to 5 or 1-5v input
using map function.
int setValue = map(ana1Value, 0, 1023, 0, 100);
could be a help for you.
the analogue input voltage is the scaled 0-100 then you can work with that

How do you watch for changes in the least significant bit?

I'm working with Arduino and am beginning to work with port registers. I love the speed increases and ability to change multiple ports at the same time. However, I don't know how to watch for a single pin changing using the port registers. (I think it can be done with bitmath, but I don't even know how to start with that.)
So when I check my port register I should get something like this:
PINB = B000xxxxx
Where x are my pin values. Any of those pins could have changed. I want to know when just the rightmost (least significant?) bit has changed. How can I use bitmath to check that just the last one has switched from a 0 to a 1?
"Bitmath" is indeed the answer to the problem. In your case: x & 0x01 will "mask" all but the lowest bit. The result can be compared to 0 or 1 at your wish.
Common idioms are:
x & 0x01 // get only the lowest bit
x & ~0x01 // clear only the lowest bit
x & 0xFE // same: clear only the lowest bit
x | 0x01 // set the lowest bit (others keep their state)
To find out if the bit has changed, you need the previous value, which you mask out as the others have said --
int lastValue = PINB & 0x01;
Then in your code you do
int currentValue = PINB & 0x01;
to get the LSB of the current pin value.
To determine if there was a change to the bit you want the "exclusive OR" (^) operator -- it is "true" if and only if the two bits are different.
if (lastValue ^ currentValue) {
// Code to execute goes here
// Now save "last" as "current" so you can detect the next change
lastValue = currentValue;
}

Resources