我正在努力使美援to在Mega2560上正常工作。每隔一段时间我就会从终端()发送的字符串()中只接收到前两个字符,或者整个字符串中缺少一个字符。我试过检查帧、波德和其他错误,但没有结果。我正在使用std::string和std::cPlusPlus库,我确实尝试使用C字符串(char数组),但是仍然存在问题,所以我不认为这会造成任何问题。
Eclipse的设置是在发送时向字符串添加一个换行符('\n'),我在执行字符串上的任何代码之前等待该字符,但仍然存在问题。我最初是从Arduino系列库开始的,但也遇到了同样的问题,更糟糕的是,这也是我选择使用AVR USART的原因。
我不知道这是否是一个问题,但我确实有2个定时器(4和5)运行,以控制我的程序的其他方面,这些可能是造成这一问题?我确实尝试过删除这些命令,但是仍然得到了相同的结果--也许我必须添加另一个命令(sei,cli)或者在某个地方设置什么东西?我希望我没有遗漏一些明显的东西,下面是相关代码。
Settings.h
const struct{
uint16_t baud = 57600;
}settings;USARTSerial
/**
* Constructor
*/
USARTSerial::USARTSerial(){
uint8_t baud = (F_CPU / (settings.baud * 16UL)) - 1;
/*** Serial Setup ***/
UBRR0H = (baud >> 8);
UBRR0L = baud;
//Transmit and receive enable
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}
/**
* Reads a single byte from the USART
*/
unsigned char USARTSerial::ReadChar(){
loop_until_bit_is_set(UCSR0A, RXC0);
//Get the received char
return UDR0;
}
/**
* Writes a single byte to the USART.
*/
void USARTSerial::WriteChar(char data){
//Wait until byte is ready to be written
while((UCSR0A & (1<<UDRE0)) == 0){}
// Transmit data
UDR0 = data;
}
/**
* Writes a std::string to the USART.
*/
void USARTSerial::Write(string data){
//Loop unit we write all the data
for (uint16_t i = 0; i < data.length(); i++){
this->WriteChar(data[i]);
}
}Main
#include "Arduino.h"
#include "avr/interrupt.h"
#include "StandardCplusplus.h"
#include "string"
#include "Settings.h"
#include "USARTSerial.h"
std::string cmdStr; /*** String to hold incoming data ***/
USARTSerial serial; /*** Serial Interface ***/
void setup(){
cli();
//Setup Timer 5
TCCR5A = 0;
TCCR5B = 0;
TCNT5 = 0;
OCR5A = 16000;
TCCR5B |= (1 << WGM52);
TCCR5B |= (0 << CS52) | (0 << CS51) | (1 << CS50);
TIMSK5 |= (1 << OCIE5A);
//Setup Timer 4
TCCR4A = 0;
TCCR4B = 0;
TCNT4 = 0;
OCR4A = 40000;
TCCR4B |= (1 << WGM12);
TCCR4B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
TIMSK4 |= (1 << OCIE4A);
serial = USARTSerial();
//Enable the Interrupts
sei();
}
/**
* ISR(Timer5 Compare A)
**/
ISR(TIMER5_COMPA_vect)
{
//Do things...
}
/**
* ISR(Timer4 Compare A)
**/
ISR(TIMER4_COMPA_vect) {
//Do some really cool stuff....
}
void loop(){
char inChar;
if(bit_is_set(UCSR0A, RXC0)){
inChar = serial.ReadChar();
//Check if we have a newline
if (inChar == '\n'){
serial.Write(cmdStr);
cmdStr = "";
}
else{
cmdStr += toupper(inChar);
}
}
}编辑
多亏了Rev1.0和tofro,我的代码终于正常工作了。的确,计时器引起了一些冲突,并将USART移动到ISR中,效果非常好。我还能够摆脱其中一个定时器,只需将操作移到主循环中。我有一个问题是关于主循环中的一个小延迟,它是否与std::stream中的the ()执行相同的操作?我知道,除非您特别希望程序等待,否则主循环中不应该有延迟,但是在我的测试中,添加延迟似乎完善了USART。下面是更新的代码..。
USARTSerial
/**
* Constructor
*/
USARTSerial::USARTSerial(){
uint8_t baud = (F_CPU / (settings.baud * 16UL)) - 1;
/*** Serial Setup ***/
UBRR0H = (baud >> 8);
UBRR0L = baud;
//Transmit and receive enable
UCSR0B |= (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0); /** Added RXCIE0 for the USART ISR **/
UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01);
}
/**
* Reads a single byte from the USART
*/
unsigned char USARTSerial::ReadChar(){
loop_until_bit_is_set(UCSR0A, RXC0);
//Get the received char
return UDR0;
}
/**
* Writes a single byte to the USART.
*/
void USARTSerial::WriteChar(char data){
//Wait until byte is ready to be written
while((UCSR0A & (1<<UDRE0)) == 0){}
// Transmit data
UDR0 = data;
}
/**
* Writes a std::string to the USART.
*/
void USARTSerial::Write(string data){
//Loop unit we write all the data
for (uint16_t i = 0; i < data.length(); i++){
this->WriteChar(data[i]);
}
}
/**
* Available
*
* Returns if the USART is ready for reading
*/
bool USARTSerial::Available(){
return bit_is_set(UCSR0A, RXC0);
}Main
#include "Arduino.h"
#include "avr/interrupt.h"
#include "StandardCplusplus.h"
#include "string"
#include "Settings.h"
#include "USARTSerial.h"
std::string cmdStr; /*** String to hold incoming data ***/
USARTSerial serial; /*** Serial Interface ***/
void setup(){
cli();
//Setup Timer 5
TCCR5A = 0;
TCCR5B = 0;
TCNT5 = 0;
OCR5A = 16000;
TCCR5B |= (1 << WGM52);
TCCR5B |= (0 << CS52) | (0 << CS51) | (1 << CS50);
TIMSK5 |= (1 << OCIE5A);
serial = USARTSerial();
//Enable the Interrupts
sei();
}
/**
* ISR(Timer5 Compare A)
**/
ISR(TIMER5_COMPA_vect)
{
//Do things...
}
/**
* Main Loop
**/
void loop(){
//Do some really cool stuff....
delay (50);
}
/**
* USART Interrupt
*/
ISR(USART0_RX_vect){
char inChar;
if(serial.Available()){
inChar = serial.ReadChar();
//Check if we have a newline
if (inChar == '\n'){
/** Run code on the recieved data ***/
cmdStr = "";
}
else{
//Convert to Uppercase
cmdStr += toupper(inChar);
}
}
} 发布于 2016-11-03 07:14:20
我会把这个作为回答,因为它太长了,不能发表评论:
我没有看到任何明显的问题,特别是当您说您从计时器ISR中删除代码以进行测试时。
但是,考虑到硬件UART使用两个字节FIFO。如果控制器接收到更多的两个字节而不读出UDR寄存器,则FIFO中的数据将丢失/覆盖。在你的情况下可能会发生这种情况。这种情况通常发生在两种情况下:
使用ISR而不是轮询RXC标志是首选的变体。
https://stackoverflow.com/questions/40390573
复制相似问题