Reputation: 11
I have a problem with SPI Interface in ATmega328p. I wrote a code that can SPI communicate with MCP3201(analog to digital converter), but I received the wrong value from MCP3201. The value should be between 600 - 700, but I get 2.
I use MCP9700(temperature sensor) to received voltage value and convert with ADC with MCP3201. I read the MCP3201' data sheet. It needs to remove trash bit. I wrote the code to show you below.
Can you check my code and schematic?
main.c
#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>
#define CS PB2
#define CS_DDR DDB2
#define MOSI DDB3
#define CLK DDB5
void USART_Init(unsigned int ubrr) {
UBRR0 = ubrr;
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
}
void USART_Transmit( unsigned char data ) {
while ( !( UCSR0A & (1 << UDRE0)) );
UDR0 = data;
}
void print(unsigned char *buffer) {
for(int i=0; buffer[i] != 0; i++){
USART_Transmit(buffer[i]);
}
}
void SPI_Init()
{
/* set MOSI CLK CS as Output*/
DDRB |= (1 << CS_DDR) | (1 << CLK) | (1 << MOSI);
// Chip select high
PORTB |= (1 << CS);
// Chip select low
PORTB &= ~(1 << CS);
/* Enable SPI, Master mode, clk/16 */
SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0);
}
uint16_t SPI_READ()
{
uint8_t rx_byte;
uint16_t rx_12bits;
PORTB &= ~(1 << CS); // Chip select low
SPDR = 0xFF; // put dummy byte in SPDR
while(!(SPSR & (1<<SPIF))); // wait for SPIF high
rx_byte = SPDR & 0b00111111; // copy SPDR out
rx_12bits = rx_byte << 7;
SPDR = 0xFF; // put dummy byte in SPDR
while(!(SPSR & (1<<SPIF))); // wait for SPIF high
rx_byte = SPDR >>= 1; // copy SPDR out
rx_12bits |= rx_byte; // Concat bit
PORTB |= (1 << CS); // Chip select high
return rx_12bits;
}
int main(void) {
USART_Init(53);
SPI_Init();
uint16_t sensor;
// uint16_t temp;
unsigned char text[] = "Temperature = ";
unsigned char buffer[10];
while (1) {
sensor = SPI_READ(); // Read data from sensor
// temp = (((sensor/4096.0) * 5) - 0.5) * 100 ;
sprintf(buffer,"%u",sensor ); // convert to string test with raw data
strcat(buffer, " °C\n");
print(text);
print(buffer);
_delay_ms(1000);
}
}
schematic
EDIT 1:
#define F_CPU 8000000L
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define CS PB2
#define CS_DDR DDB2
#define MOSI DDB3
#define CLK DDB5
void USART_Init(unsigned int ubrr) {
UBRR0 = ubrr;
UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
}
void USART_Transmit( unsigned char data ) {
while ( !( UCSR0A & (1 << UDRE0)) );
UDR0 = data;
}
void print(unsigned char *buffer) {
for(int i=0; buffer[i] != 0; i++){
USART_Transmit(buffer[i]);
}
}
void SPI_Init()
{
/* set MOSI CLK CS as Output*/
DDRB |= (1 << CS_DDR) | (1 << CLK) | (1 << MOSI);
// Chip select high
PORTB |= (1 << CS);
// Chip select low
PORTB &= ~(1 << CS);
/* Enable SPI, Master mode, clk/16 */
SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0);
}
uint16_t SPI_READ()
{
uint16_t high_byte;
uint16_t low_byte;
uint16_t out_12bits;
PORTB &= ~(1 << CS); // Chip select low
SPDR = 0xFF; // put dummy byte in SPDR
while(!(SPSR & (1<<SPIF))); // wait for SPIF high
/*xx0[B11][B10][B9][B8][B7]*/
high_byte = SPDR; // copy SPDR out
SPDR = 0xFF; // put dummy byte in SPDR
while(!(SPSR & (1<<SPIF))); // wait for SPIF high
/*[B6][B5][B4][B3][B2][B1][B0][B1]*/
low_byte = SPDR; // copy SPDR out
/*xx0[B11][B10][B9][B8][B7] 0 0 0 0 0 0 0 0 */
/* OR */
/*000 0 0 0 0 0 [B6][B5][B4][B3][B2][B1][B0][B1]*/
/*---------------------------------------------------------*/
/*xx0[B11][B10][B9][B8][B7][B6][B5][B4][B3][B2][B1][B0][B1]*/
out_12bits = (high_byte << 8) | low_byte; // Concatenate bit
/*[B11][B10][B9][B8][B7][B6][B5][B4][B3][B2][B1][B0][B1]000*/
out_12bits <<= 3; // Shift left 3
/*0000[B11][B10][B9][B8][B7][B6][B5][B4][B3][B2][B1][B0]*/
out_12bits >>= 4; // Shift right 4
PORTB |= (1 << CS); // Chip select high
return out_12bits;
}
int main(void) {
USART_Init(53); // SPI intial
SPI_Init(); // USART initial
uint16_t sensor;
float temp;
unsigned char text[] = "Temperature = ";
unsigned char buffer[10];
while (1) {
sensor = SPI_READ(); // Read data from sensor
temp = (((sensor/4096.0) * 5.0) - 0.5) * 100.0 ; // Convert Analog value to temperature
dtostrf(temp, 3, 2, buffer); // Convert Float to string
strcat(buffer, " °C\n"); // Concatenate unit
print(text); // Print First Text
print(buffer); // Print temperature and unit
_delay_ms(1000);
}
}
Upvotes: 1
Views: 615
Reputation: 821
Actually i do not have the chance to test the code, but maybe this helps:
#define F_CPU 8000000L
#define BAUD 9600UL // Used within setbaud.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/setbaud.h>
#define CS PB2
#define MOSI PB3
#define MISO PB4
#define CLK PB5
void uart_init() {
#if USE_2X // Defined within setbaud.h
UCSRA |= (1<<U2X); // Setup 8 samples/bit
#else
UCSRA &= ~(1<<U2X); // Setup 16 samples/bit
#endif
UBRR0 = UBRRH_VALUE; // Defined within setbaud.h
UCSR0B |= (1<<RXEN0) | (1<<TXEN0);
UCSR0C |= (1<<UCSZ01) | (1<<UCSZ00);
}
void uart_transmit(unsigned char data ) {
while (!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
}
void print(unsigned char *buffer) {
for(unsigned int i=0; buffer[i] != 0; i++){
uart_transmit(buffer[i]);
}
}
void spi_init()
{
// Set MISO and Chip Select as Input
DDRB &= ~((1<<CS) | (1<<MISO));
// Set pullup resistors for MISO and Chip Select
PORTB |= (1<<CS) | (1<<MISO);
// SPI
// - Mode: Master
// - Prescaler: 16
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
// Setup SCK, MOSI and SS as output
// PORT configuration gets overwritten from SPI controller
DDRB &= (1<<CLK) | (1<<MOSI) | (1<<CS);
}
void spi_select()
{
DDRB &= ~(1<<CS);
}
void spi_deselect()
{
DDRB |= (1<<CS);
}
unsigned char spi_read()
{
SPDR = 0xFF; // Write data into the SPI Data Register and initiate a transmission
// Wait until transmission is Complete
while(!(SPSR & (1<<SPIF)))
asm volatile("NOP");
return SPDR
}
unsigned int mcp3201_data()
{
spi_select();
unsigned char high_data = spi_read();
unsigned char low_data = spi_read();
spi_deselect();
// +-------------------------------+-------------------------------+
// | HIGH | LOW |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | - | - | - | - | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? |
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
//
// Value between 0 to (2^12 - 1) = 0 to 4095
return (((high_data & 0x0F)<<8) | low_data);
}
int main(void) {
uart_init();
spi_init();
const unsigned char text[] = "Temperature = ";
unsigned char buffer[100];
while (1)
{
unsigned int mv; = ((mcp3201_data * 5000)>>12); // Analog Voltage in mV
double temp = mv; // Calculate your temperature
dtostrf(temp, 3, 2, buffer); // Convert Float to string
strcat(buffer, " °C\n"); // Concatenate unit
print(text); // Print First Text
print(buffer); // Print temperature and unit
_delay_ms(1000);
}
}
Indeed i have not calculated the temperature. Thats your turn...
Upvotes: 0