How to read 32 bits variable from Software SPI in ATmega32? - c

it is my first try to set up SPI communication on ATmega32 and MAX31855. I've to read 32 bits from MAX31855 datasheet. I have writen my own function but it seems to read 0 all time (I have checked it on display). Here are my definitions from *.h file:
#ifndef SPI_SOFTWARE_H_
#define SPI_SOFTWARE_H_
#define ilosc_urzadzen 1
#define SoftSPI_MOSI PD0
#define SoftSPI_MISO PD1
#define SoftSPI_SCK PD2
#define SoftSPI_CS1 PD3
#define SoftSPI_CS2 PD4
#define SoftSPI_CS3 PD5
#define SoftSPI_CS4 PD6
#define SoftSPI_CS5 PD7
#define SoftSPI_DDR DDRD
#define SoftSPI_PIN PIND
#define SoftSPI_PORT PORTD
void init_SoftSPI();
uint32_t odczyt32bit(int CSx);
#endif
I have connected MAX31855: SO -> PD1, SCK -> PD2, CS -> PD3.
And here is my code from *.c:
#include <avr/io.h>
#include "SPI_software.h"
void init_SoftSPI(){
SoftSPI_DDR |= (1 << SoftSPI_MOSI) | (1 << SoftSPI_SCK);
if(ilosc_urzadzen == 1) SoftSPI_DDR |= (1 << SoftSPI_CS1);
else if(ilosc_urzadzen == 2) SoftSPI_DDR |= (1 << SoftSPI_CS1) | (1 << SoftSPI_CS2);
else if(ilosc_urzadzen == 3) SoftSPI_DDR |= (1 << SoftSPI_CS1) | (1 << SoftSPI_CS2) | (1 << SoftSPI_CS3);
else if(ilosc_urzadzen == 4) SoftSPI_DDR |= (1 << SoftSPI_CS1) | (1 << SoftSPI_CS2) | (1 << SoftSPI_CS3) | (1 << SoftSPI_CS4);
else if(ilosc_urzadzen == 5) SoftSPI_DDR |= (1 << SoftSPI_CS1) | (1 << SoftSPI_CS2) | (1 << SoftSPI_CS3) | (1 << SoftSPI_CS4) | (1 << SoftSPI_CS5);
}
uint32_t odczyt32bit(int CSx){
uint32_t liczba = 0;
if (CSx == 1){
SoftSPI_PORT &= ~SoftSPI_CS1;
for (int i = 0; i < 32; i++)
{
SoftSPI_PORT |= SoftSPI_SCK;
if (SoftSPI_PIN & (1 << SoftSPI_MISO)) liczba += 1;
liczba = liczba << 1;
SoftSPI_PORT &= ~SoftSPI_SCK;
}
SoftSPI_PORT |= SoftSPI_CS1;
}
return liczba;
}
After reading value from MAX31855 I shift it (20 places no 18 becouse I dont need fraction part):
temp = odczyt32bit(1);
temp = temp >> 20;
Where is my problem?

The clocking timing looks okay, but note that you only need to clock out 14 cycles (or just 12 for less precision) to get the result. You can stop reading the rest of the results whenever you want. (You don't need to read all 32 bits if you aren't using them.) If you do read all the bits, then you can detect any fault codes that indicate the thermocouple is not connected correctly.
Are you giving enough time for the conversion to occur? It needs 100 ms between readings.

Related

register manipulation avr microcontroller

I'm just starting out. Have a little patience for my questions.
I came across a listing of a program where the following statement appears:
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2));
My guess:
considering that at startup the microcontroller has by default the DDRB bits all set to 0, I get:
DDRB & = ~ ((1 << 0) | (1 << 0) | (1 << 0)); ===>> DDRB & = ~ ((1) | (1) | (1));
which is different from the author's cooment. Where am I wrong?
2 # question: recital
volatile uint8_t portbhistory = 0xFF;
changedbits = PINB ^ portbhistory;
the second statement is not equal to:
changedbits = ~ PINB;
what changes? thanks to those who want to answer me.
No it is DDRB & = ~ ((1 << 0) | (1 << 1) | (1 << 2));
DDB0, DDB1, DDB2 are bit numbers defined in header file.
#define DDB0 0
#define DDB1 1
/* ... actual values may be different */
Statement:
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2));
zeroes DDB0, DDB1 & DDB2 bits.
DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB2);
sets DDB0, DDB1 & DDB2 bits.
DDRB ^= (1 << DDB0) | (1 << DDB1) | (1 << DDB2);
toggles DDB0, DDB1 & DDB2 bits (sets their value to the opposite one).

atmega2650 toggling OC1C (led on arduino mega)

I am trying to toggle an LED with a 1024 prescaler, CTC mode 4.
The LED comes on after a second and stays on.
What am I doing wrong?
#include "Arduino.h"
void setup() {
//PORTB ^= (0 << PB7);
DDRB = (1 << PB7);
TCNT1 = 0;
OCR1C = 100;
TCCR1A = 0; // thought maybe arduino was setting other bits?
TCCR1B = 0; //
TCCR1A = (0 << COM1C1) | (1 << COM1C0) | (0 << WGM11) | (0 << WGM10);
TCCR1B = (0 << WGM13) | (1 << WGM12) | (1 << CS12) | (0 << CS11) | (1 << CS10);
}
void loop() {}
UPDATE
#include "Arduino.h"
void setup() {
//PORTB ^= (0 << PB7);
DDRB = (1 << PB7);
TCNT1 = 0;
TCCR1A = 0; //
TCCR1B = 0; //
OCR1A = 100; // OCR1A is the CTC mode 4 top
TCCR1A = (0 << COM1C1) | (1 << COM1C0) | (0 << WGM11) | (0 << WGM10);
TCCR1B = (0 << WGM13) | (1 << WGM12) | (1 << CS12) | (0 << CS11) | (1 << CS10);
}
void loop() {}
Set OCR1A after clearing the TCCR1A and TCCR1B
As Mike said OCR1A is top for mode 4

Atmega2560 PWM on PB7

I am trying to get PWM output from PB7 pin with timer0 on Atmega2560 with no luck. It should generate tone for the connected repro.My PWM settings are:
DDRB = 0b11100000;
PORTB = 0b00000000;
OCR0A = 0x04;
TCCR0A = (0 << COM0A1) | (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);
TCCR0B = (0 << WGM02) | (0 << CS02) | (0 << CS01) | (0 << CS00);
and then I have this function, which should generate the sound:
void SoundOutput(unsigned int uintTone)
{
if (uintTone != 0)
{
LED_2(1);
OCR0A = uintTone;
TCCR0B |= (1 << CS02) | (1 << CS01) | (1 << CS00);
}
else
{
TCCR0B &= ~((1 << CS02) | (1 << CS01) | (1 << CS00));
}
}
but nothing happens when i call it with tone parameter. Can you please help me?
Based on your comments, you are using ~12MHz clock as the input to your timer, and from your code, you are using 8 bit timer 0 in CTC mode with OCR0A as your top. You have OC0A set to toggle on a compare match.
According to the 2560 datasheet, the frequency of your timer is given by:
F_CLK/(2*(1 + OCR0A)) | F_CLK ~= 12MHz
This is an 8 bit timer, so that means that your minimum frequency that your PWM can generate is given by:
12e6/(2*(1 + 255)) ~= 20KHz
You simply aren't going to be able to generate an audible tone with that configuration unless you slow down the clock you are using for your timer or use a timer that can count higher.
1) Use a 16 bit counter (i.e. timer1). That will give you a min frequency of ~90Hz and a max frequency of ~6MHz, which should give you plenty of range to generate tones:
/* WGM BITS = 0100: CTC Mode */
/* COMA BITS = 01: Toggle OC1A on compare match */
/* CS BITS = 111: External clock source on rising edge */
TCCR1A = (0 << COM1A1) | (1 << COM1A0) | (0 << WGM01) | (0 << WGM00);
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS02) | (1 << CS01) | (1 << CS00);
2) Use the internal clock source as the timer clock instead of an external source. Unless you changed fuse bits or you are changing it in the code somewhere, the clock will be 1MHz. Prescaling the clock by 8 gives you a frequency range of ~250Hz - ~60KHz.
/* WGM BITS = 010: CTC Mode */
/* COMA BITS = 01: Toggle OC1A on compare match */
/* CS BITS = 010: Prescale the internal clock by 8 */
TCCR0A = (0 << COM0A1) | (1 << COM0A0) | (1 << WGM01) | (0 << WGM00);
TCCR0B = (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00);

Atmega16 USART initialization

I can't for the life of me find why this code is not working to send a byte to my computer terminal window. It receives and works fine when I omit that line though. Receiving and sending also work seperately. Please note that this is over rs485 so I must disable TXEN if I want anything received to make it through the line driver ic.
#define F_CPU 7800000UL // 7.8 MHz
#include <avr/io.h>
//#include <util/delay.h>
#include <avr/interrupt.h>
#include <math.h>
#define USART_BAUDRATE 57600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
volatile unsigned int value = 0;
volatile int recievearray[4] = {0,0,0,0};
volatile int x=0;
void USART_Init(void)
{
DDRD = 0x7E; //you have to assign TXEN as output for some reason
//PORTD = 0xFF;
UCSRB = 0;
//Put the upper part of the baud number here (bits 8 to 11)
UBRRH = (unsigned char) (BAUD_PRESCALE >> 8);
//Put the remaining part of the baud number here
UBRRL = (unsigned char) BAUD_PRESCALE;
//PORTD = 2;
// ASYNCRONOUS
UCSRC = (0 << UMSEL);
//Enable the receiver and transmitter
UCSRB = (1 << RXEN) | (1 << TXEN) | (0 << UCSZ2) | (1<<RXCIE);
//Set 1 stop bits and data bit length is 8-bit
UCSRC = (1 << URSEL) | (0 << USBS) | (3 << UCSZ0);
//no parity
UCSRC |= (0 << UPM1);
UCSRC |= (0 << UPM0);
}
void USART_SendByte(uint8_t u8Data)
{
UCSRB = (1 << TXEN) | (1<<TXCIE);
// Wait until last byte has been transmitted
while((UCSRA &(1<<UDRE))==0);
UDR = u8Data;
UCSRB = (0 << TXEN) | (0<<TXCIE);
}
void Led_init(void){
DDRC = 0xFF;
}
ISR(USART_RXC_vect)
{
//PORTC = 0xFF;
while((UCSRA &(1<<RXC)) == 0);
value = UDR;
if (x < 4)
{
recievearray[x++] = value;
}
else
{
x = 0;
recievearray[x++] = value;
PORTC = 0x00;
}
}
int main(void)
{
USART_Init();
sei();
Led_init();
//PORTC = 0xFF;
for(;;)
{
if (recievearray[0] + recievearray[1] + recievearray[2] + recievearray[3] > 100)
{
PORTC = 0xFF;
USART_SendByte(value);
}
//_delay_ms(1000);
}
}

ATMEGA168A - Using timer

I am trying to understand how to use timers with my ATMEGA168A, however the example I have (link) doesn't seem to work since it returns 0 all the time.
My idea is to make a HC-SR04 (link) ultra sound sensor work.
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
long measure(){
//Setting up the timer
TCCR1B |= (1 << CS12) | (1 << CS11) | (1 << CS10);
//Setting trigger as output
DDRD |= (1 << PD1);
//Setting echo as input
PORTD |= (1 << PD2);
//Triggering the hardware
PORTD ^= (1 << PD1);
_delay_us(10);
PORTD ^= (1 << PD1);
//Waiting until echo goes low
TCNT1 = 0;
while(bit_is_clear(PIND, PD2));
long timer_value = TCNT1;
//Calculating and returning the distance
long distance = timer_value / 58.82;
return distance;
}
How can I successfully measure the amount of time the PD2 was high?
To measure the amount of time the PD2 was high, write some code to do so, compile, write it to your microcontroller and turn on it.
Not tested, try this:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
long measure(){
//Setting up the timer
TCCR1B |= (1 << CS12) | (1 << CS11) | (1 << CS10);
//Setting trigger as output
DDRD |= (1 << PD1);
//Setting echo as input
PORTD |= (1 << PD2);
//Triggering the hardware
PORTD ^= (1 << PD1);
_delay_us(10);
PORTD ^= (1 << PD1);
//Waiting until echo goes low (after Initiate)
while(!bit_is_clear(PIND, PD2));
//Waiting until echo goes high (Echo back starts)
while(bit_is_clear(PIND, PD2));
TCNT1 = 0;
//Waiting until echo goes low (Echo back ends)
while(!bit_is_clear(PIND, PD2));
long timer_value = TCNT1;
//Calculating and returning the distance
long distance = timer_value / 58.82;
return distance;
}

Resources