基于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
相关产品推荐
相关产品推荐

