I implemented the following program to send data to a serial monitor.When I run it, I expect to see abcd
but I always see ⸮bcd
:
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define BAUD 9600
#define CLKPS 8
#define F_CPU 16000000UL
#define TCNT0_VALUE (0xFF - F_CPU / CLKPS / BAUD)
static volatile uint8_t bit = 0;
static volatile uint16_t data = 0;
static volatile int tx_in_progress = 0;
static void swuart_init(uint8_t tx_pin)
{
// initialize timer
TCNT0 = TCNT0_VALUE;
TCCR0A = 0x00;
TCCR0B = 1 << CS01;
TIMSK0 = 1 << TOIE0;
// enable tx pin
DDRD |= (1 << tx_pin);
}
/* set up payload: 1 start bit, 0 parity bits, 1 stop bit */
static void swuart_send_byte(uint8_t byte)
{
tx_in_progress = 1;
data = (1 << 10) | ((uint16_t) byte << 1);
while (tx_in_progress)
;
}
int main(void)
{
swuart_init(PD7);
sei();
swuart_send_byte('a');
swuart_send_byte('b');
swuart_send_byte('c');
swuart_send_byte('d');
for (;;)
;
return 0;
}
ISR(TIMER0_OVF_vect)
{
TCNT0 = TCNT0_VALUE;
if (!tx_in_progress)
return;
if (data & (1 << bit))
PORTD |= (1 << PD7);
else
PORTD &= ~(1 << PD7);
if (bit < 10)
bit++;
else {
bit = 0;
tx_in_progress = 0;
}
}
-
1\$\begingroup\$ What if you add a short delay between calling the setup and starting output? You could be causing some glitching that looks like a start bit. \$\endgroup\$hobbs– hobbs2023年04月07日 05:05:36 +00:00Commented Apr 7, 2023 at 5:05
-
\$\begingroup\$ @hobbs It is causing a glitch that looks like a start bit. \$\endgroup\$Justme– Justme2023年04月07日 05:10:07 +00:00Commented Apr 7, 2023 at 5:10
1 Answer 1
The problem is that the pin is uninitialized, and you send a byte immediately after pin is initialized.
And the pin is incorrectly initialized to logic low, which is a start bit.
Initialize the pin as a high output, not as a low output. You might want to delay at least 10 bits worth of time to make sure that situation after boot and reset has stabilized before start bit of first byte can be sent.
It is also a hazard to set the transmit flag first and then set the data what to transmit. The interrupt might trigger between setting the flag and setting what data to send.