问题描述
我在 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);
}
}
示意图
编辑 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);
}
}
解决方法
实际上我没有机会测试代码,但也许这有帮助:
#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);
}
}
确实我没有计算温度。轮到你了...