簡體   English   中英

AVR ATmega328p 和 MCP3201 問題

[英]AVR ATmega328p and MCP3201 issue

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, 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);
    }
}

實際上我沒有機會測試代碼,但這可能會有所幫助:


#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);
    }
}

事實上,我還沒有計算溫度。 輪到你了……

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM