断続的なバグで髪を引っ張っています。(PIC16F77 で) バイトを非同期的に送受信しており、送受信用の循環ソフトウェア FIFO バッファを実装し、バイトを送信できるか受信したときにトリガーされる割り込みサービス ルーチンと組み合わせました。
問題は、送信されるバイトが間違った順序で送信されることがあるということです。
次のいずれかをいただければ幸いです。
- デバッグに関するアドバイス、または
- コードの問題を見つける支援
これまでの進捗状況:
- いくつかのバイトが受信されている場合にのみ発生するようですが、さらに絞り込むことに失敗しました。私の知る限り、アンダーランやオーバーランは発生していません。
- 次のいずれかに変更
send_char()
すると、問題なく動作します: 1. ハードウェア バッファーのスペースを待って、バイトを直接入れることによってソフトウェア バッファーをバイパスするか、2. ハードウェアにスペースがある場合でも、バイトをソフトウェア バッファーに入れます。バッファ。
コード: (ハードウェア変数の説明については、質問の下部を参照してください)
unsigned volatile char volatile rc_buff[16];
unsigned char volatile rc_begin = 0;
unsigned char volatile rc_next_free = 0;
unsigned char volatile rc_count = 0;
unsigned volatile char volatile tx_buff[16];
unsigned char volatile tx_begin = 0;
unsigned char volatile tx_next_free = 0;
unsigned char volatile tx_count = 0;
__interrupt isr(){
// If a character has arrived in the hardware buffer
if (RCIF){
// Put it in the software buffer
if (rc_count >= 16) die(ERROR_RC_OVERFLOW);
rc_buff[rc_next_free] = RCREG;
rc_next_free = (rc_next_free + 1) % 16;
rc_count++;
}
// If there is space in hardware FIFO, and interrupt
// has been enabled because stuff in software FIFO needs to be sent.
if (TXIE && TXIF){
// Put a byte from s/w fifo to h/w fifo.
// (Here, tx_count is always > 0 (in theory))
TXREG = tx_buff[tx_begin];
tx_count--;
tx_begin = (tx_begin + 1) % 16;
// If this was the last byte in the s/w FIFO,
// disable the interrupt: we don't care
// when it has finished sending.
if(tx_count==0) TXIE = 0;
}
}
void send_char(char c){
// disable interrupts to avoid bad things happening
di();
// if the hardware buffer is empty,
if (TXIF){
// put a byte directly into the hardware FIFO
TXREG = c;
} else {
// cannot send byte directly so put in the software FIFO
if (tx_count >= 16) die(ERROR_TX_OVERFLOW);
tx_buff[tx_next_free] = c;
tx_next_free = (tx_next_free + 1) % 16;
tx_count++;
// Enable TX interrupt since it now has something
// it needs to transfer from the s/w FIFO to the h/w FIFO
TXIE = 1;
}
ei();
}
char get_char(){
// wait for a byte to appear in the s/w buffer
while (!rc_count) {
// If the h/w buffer overflowed, die with error
if (OERR) die(ERROR_RC_HW_OVERFLOW)
}
// disable interrupts to avoid bad things happening
di();
unsigned char c = rc_buff[rc_begin];
rc_count--;
rc_begin = (rc_begin + 1) % 16;
ei();
return c;
}
void send_str(const unsigned char * str){
unsigned char char_idx = 0;
// until we reach the end-of-string null character,
while (str[char_idx]){
// queue a character for sending
send_char(str[char_idx++]);
}
}
ハードウェア変数の説明:
参考までに、ハードウェア レジスタとフラグにマップされる (揮発性) 変数を次に示します。
RCIF // Read-only receive flag: True == byte(s) are waiting in hardware receive FIFO
TXIF // Read-only transmit flag: True == there is space in the hardware transmit FIFO
RCREG // Read only: Holds the next byte from the hardware FIFO that has been received
TXREG // Write-only: Assigning a byte to this transfers the byte to the hardware transmit FIFO
TXIE // Read/Write: Enable transmit interrupt: True == trigger ISR when TX h/w FIFO has space
RCIE // Read/Write: Enable receive interrupt: True == trigger ISR when RC h/w FIFO has a byte to be read
また、以下は、複数のグループ化された操作をアトミックに保つために割り込みを一時停止/再開する特別なインライン関数です。(ISR は、他の割り込みを含め、何によっても中断できません)
di() // suspend interrupts
ei() // re-enable interrupts