You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ATmega32A的光谱仪ADC串口输出异常问题排查求助

问题描述

计划搭建一台光谱仪,通过MG995伺服电机旋转光栅,S9055系列3引脚光电二极管捕获光强,最终用Python绘制光强-旋转角度曲线。硬件采用AVR ATmega32A单片机,MG995电机工作正常,但ADC数据通过串口发送到PuTTY终端时显示乱码。

项目流程:

  • 采用白光源与光栅,光电二极管捕获经光栅衍射的光线
  • MG995电机通过OC1A引脚连接单片机,每次旋转小角度并延时
  • 光电二极管经跨阻运放连接ADC0引脚,将数据传输至PuTTY终端
  • 将数据整理为DataFrame并绘制曲线

以下是捕获光强并转换数值的代码:

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdio.h>

//#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)


void UART_init(long USART_BAUDRATE)
{
    UCSRB |= (1 << RXEN) | (1 << TXEN);   /* Turn on the transmission and reception */
    UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); /* Use 8-bit character sizes */

    UBRRL = BAUD_PRESCALE;                  /* Load lower 8-bits of the baud rate value */
    UBRRH = (BAUD_PRESCALE >> 8);           /*Load upper 8-bits*/
}



void UART_TxChar(char ch)
{
    while (! (UCSRA & (1<<UDRE))); /*Wait for empty transmit buffer*/
    UDR = ch ;
}

void UART_SendString(char *str)
{
    unsigned char j=0;
    
    while (str[j]!=0)   /*send string up to null */
    {
        UART_TxChar(str[j]);    
        j++;
    }
}

void adc_init() // Initialize ADC
{
    ADMUX = (1<<REFS0); // AVCC as reference voltage
    ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Enable ADC and set prescaler to 128
}

// Function to read the ADC value
// Read ADC value from a channel
uint16_t adc_read(uint8_t channel)
{
    channel &= 0x07; // Select channel from 0 to 7
    ADMUX = (ADMUX & 0xF8) | channel; // Clear the lower 3 bits and set the channel
    ADCSRA |= (1<<ADSC); // Start conversion
    while(ADCSRA & (1<<ADSC)); // Wait for conversion to complete
    return ADC; // Return the ADC value
}

int main()
{
    uint16_t adc_value; // Variable to store the ADC value
    //DDRB = 0xFF; // Set PORTB as output for LED display
    adc_init(); // Initialize ADC
    
    char c="5";
    UART_init(9600);
    
    UART_SendString("\nInitializing....\n ");   
    while(1)
    {
         adc_value = adc_read(0); // Read ADC value from channel 0 (connected to photodiode)

        // Print the ADC value to the Putty terminal
        printf("ADC value: %d\n", adc_value);
        UART_SendString(c );        
        UART_SendString(adc_value );

        // Wait for a millisecond
        _delay_ms(1000);


    }   
    return 0;
}
}
错误排查与修复

串口乱码核心由波特率不匹配、类型错误、函数使用不当导致,具体问题及修复方案如下:

1. 波特率计算错误

代码中#define USART_BAUDRATE 9600被注释,导致BAUD_PRESCALE计算时USART_BAUDRATE未定义,编译后波特率完全错误,直接引发乱码。
修复:取消注释#define USART_BAUDRATE 9600,确保波特率计算逻辑正常。

2. 变量类型不匹配

  • char c="5";:"5"是字符串常量(char*类型),赋值给char变量会导致内存地址错误,引发未知行为。
    修复:改为char *c="5";(字符串指针)或char c='5';(单个字符);若用单个字符,需修改发送逻辑为UART_TxChar(c);。
  • UART_SendString(adc_value);:adc_value是uint16_t数值,UART_SendString需要char*类型,直接传数值会把数值当作内存地址,读取乱码内容发送。
    修复:用itoa函数将数值转为字符串后发送:
    char adc_str[6]; // 足够存储0-1023的十进制字符串
    itoa(adc_value, adc_str, 10); // 十进制格式转换
    UART_SendString(adc_str);
    

3. printf未重定向

代码中直接调用printf,但未将其输出重定向到串口,printf默认输出到标准输出(AVR无硬件支持),因此该部分代码无效。
修复:实现putchar函数,将printf输出重定向到UART:

int putchar(char c) {
    UART_TxChar(c);
    return c;
}

之后即可正常使用printf发送格式化字符串。

4. 语法错误

代码末尾多了一个},会导致编译失败,需删除多余的括号。

修复后的main函数示例

int main()
{
    uint16_t adc_value;
    char adc_str[6];
    char *c = "5";
    
    adc_init();
    UART_init(9600);
    
    UART_SendString("\nInitializing....\n ");   
    while(1)
    {
         adc_value = adc_read(0);

         // 使用printf发送格式化内容(需先实现putchar)
         printf("ADC value: %d\n", adc_value);
         
         // 发送字符串c和转换后的ADC值
         UART_SendString(c);
         itoa(adc_value, adc_str, 10);
         UART_SendString(adc_str);
         UART_SendString("\n"); // 添加换行区分数据

         _delay_ms(1000);
    }   
    return 0;
}

内容的提问来源于stack exchange,提问作者Fernando V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:54:54