问题描述
我在 ATmega328p 中的 SPI 接口有问题。我写了一个可以与 MCP3201(模数转换器)进行 SPI 通信的代码,但是我从 MCP3201 收到了错误的值。值应该在 600 - 700 之间,但我得到 2。
我使用 MCP9700(温度传感器)接收电压值并使用 MCP3201 使用 ADC 进行转换。我阅读了 MCP3201 的数据手册。它需要去除垃圾位。我写了下面的代码给你看。
你能检查一下我的代码和原理图吗?
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); } }
@H_502_11@示意图
编辑 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,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); } }
@H_502_11@解决方法
实际上我没有机会测试代码,但也许这有帮助:
#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); } }
确实我没有计算温度。轮到你了...