Atmega 2560 USART not giving correct value on terminal - serial-port

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.

Related

The adc function on attiny44 not working as needed?

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.

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.

12-bit ADC in MSP430FR2476 seems to only work in 10-bit mode

Here is the problem: I am trying to initialize the 12-bit built-in ADC on MSP430FR2476, but no matter what I do it seems to work at 10 bits. I change the resolution bits in a control register and alas, to no avail. No matter what I have tried nothing helps, always 10 bits. The most significant byte never gets higher than 3. Please help, here is a snippet of the code:
//Configuring ADC
PMMCTL2 |= (INTREFEN); //Internal reference, default 1.5V
ADCCTL0=ADCCTL1 = 0; //Ensuring that the ADC is off
ADCCTL0 |= (ADCSHT_7 + ADCMSC); //sample and hold = 64clk, multiple conversion
ADCCTL1 |= (ADCSHP + ADCSSEL_2 + ADCCONSEQ_1 + ADCDIV_7); //Conversion is triggered
//manually, ADC clock source - SMCLK/8 ~ 2Mhz, sequence of
//channels single conversion,
ADCCTL2 |= (ADCRES_2); //12 bit resolution, no matter what setting I have, no change
ADCMCTL0 |= (ADCSREF_1 + ADCINCH_1); //Employing the internal reference and starting
//conversion from A1 (P1.1)
ADCIE |= ADCIE0; //Activate interrupt
ADCCTL0 |= (ADCON); //Switching ADC on
SYSCFG2 |= (BIT1); //Activate ADC module on the pins (this line
//doesn't do anything for some reason
void adc_convert_begin(){
ADCCTL0 |= ADCENC;
ADCCTL0 |= ADCSC; //Start conversion
//The interrupt simpy send the most significant byte over UART
__attribute__((interrupt(ADC_VECTOR)))
void ADC_ISR(void){
switch(__even_in_range (ADCIV, 0x0C)){
case 0x0C:
adc_data[adc_index] = ADCMEM0;
UCA1TXBUF = (unsigned char)(ADCMEM0>>8);
break;
}
}
The error happens to be here:
ADCCTL2 |= (ADCRES_2);
The idea is the default value is 1, so when I perform an |= operation on the register, the final value turns out to be 3, instead of 2. I need to zero that bit field first!

Why i can not receive string from USART using this code?

After using this code i am not getting anything on serial monitor while it should give me the string which i am sending .am i right that strings which i am sending from serial monitor are null terminated in arduino (and that's why i am waiting for null character in order to get the string) ? Please help
void setup()
{
UBRR0 = 103; // for configuring baud rate of 9600bps
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
// Use 8-bit character sizes
UCSR0B |= (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
//// Turn on the transmission, reception, and Receive interrupt
sei();// enable global interrupt
}
ISR(USART_RX_vect)
{
while (1)
{
while (!(UCSR0A & (1 << RXC0)));
if (UDR0 != '\0')
{
buf[i] = UDR0;
i++;
}
else
{
break;
}
}
temp=String(buf);
uart_send_string(temp); //this function is working properly
}
No, you won't receive a null '\0' character usually.
Unless the sender explicitly sends one. But this is unusual for non-binary data transmission via Serial. The SerialMonitor definitely doesn't!
If you need to notice the end of a message, a newline ( LF , '\n' or 0x0A ) is very common. But any other character might do as well.
BTW: As you tag the question Arduino, why don't you use the Arduino library for Serial UART communication?

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)

Resources