Skriver C för tiny45 med AVR Studio 4
Lite analyserande med logikanalysatorn gav:

Allt ser snyggt och rätt ut!

Men om man zoomar in vid triggpunkten ser man att det händer något innan! Vad är denna dip för något? Har försökt isolera felet men utan framgång... Någon som har lite ideer?
main.c
Kod: Markera allt
#include <avr/io.h>
#include <avr/interrupt.h>
#include "SwUART.h"
int main(void) {
int i;
InitSwUART(); // init UART
sei(); // enable interrupts
DDRB |= (1 << PB0);
PORTB &= ~(1 << PB0); // toggle PB0 (trig)
PORTB |= (1 << PB0);
PORTB &= ~(1 << PB0);
unsigned char a[] = {0xFF, 0x00, 0x01, 0x82, 0x83};
for(i = 0; i < 5; i++) {
put_char(a[i]);
}
while(1) {
}
}
Kod: Markera allt
// Some I/O and interrupt specific defines (hardware setup)
#define TX_PIN PB4
#define RX_PIN PB2 // INT0 have to be on this pin...
#define TRXDDR DDRB
#define TRXPORT PORTB
#define TRXPIN PINB
#define ENABLE_TIMER_INTERRUPT() (TIMSK |= (1 << OCIE0A))
#define DISABLE_TIMER_INTERRUPT() (TIMSK &= ~(1 << OCIE0A))
#define ENABLE_EXTERNAL_INTERRUPT() (GIMSK |= (1 << INT0))
#define DISABLE_EXTERNAL_INTERRUPT() (GIMSK &= ~(1 << INT0))
#define SET_TX_PIN() (TRXPORT |= (1 << TX_PIN))
#define CLEAR_TX_PIN() (TRXPORT &= ~(1 << TX_PIN))
#define GET_RX_PIN() (TRXPIN & (1 << RX_PIN))
#define TICK_ONEANDHALF 75
#define TICK_ONE 50
// Functions
void InitSwUART(void);
void put_char(const unsigned char c);
void print_string(const unsigned char *data);
// Variables
typedef enum {
IDLE,
TRANSMIT,
RECEIVE,
DATA_PENDING
}states;
static volatile states SwUART_state;
static volatile unsigned char SwUART_TXData;
static volatile unsigned char SwUART_TXBitCount;
static volatile unsigned char SwUART_RXData;
static volatile unsigned char SwUART_RXBitCount;
SwUART.c
Kod: Markera allt
// 8MHz clock and 19200 as baudrate designed for ATtiny45
// No parity bit, 8 data bits, 1 stop bit
#include <avr/io.h>
#include <avr/interrupt.h>
#include "SwUART.h"
ISR(TIM0_COMPA_vect) { // timer interrupt handler
// transmit byte
if(SwUART_state == TRANSMIT) {
if(SwUART_TXBitCount < 8) {
if(SwUART_TXData & 0x01) {
SET_TX_PIN(); // send a logic 1
}
else {
CLEAR_TX_PIN(); // send a logic 0
}
SwUART_TXData = SwUART_TXData >> 1;
SwUART_TXBitCount++;
}
// send stop bit
else if(SwUART_TXBitCount == 8) {
SET_TX_PIN();
SwUART_TXBitCount++;
}
// done transmitting
else {
DISABLE_TIMER_INTERRUPT();
SwUART_state = IDLE;
}
}
// receive byte
else if(SwUART_state == RECEIVE) {
OCR0A = TICK_ONE; // count one period
// receiving, LSB first
if(SwUART_RXBitCount < 8) {
if(GET_RX_PIN() != 0) {
SwUART_RXData = 0x80; // if a logic one let the data mirror this
}
SwUART_RXData = (SwUART_RXData >> 1); // shift due to LSB first
SwUART_RXBitCount++;
}
// done receiving
else {
SwUART_state = DATA_PENDING; // one byte received enter DATA_PENDING
DISABLE_TIMER_INTERRUPT();
GIFR |= (1 << INTF0); // reset flag to not enter external intrrupt one extra time
ENABLE_EXTERNAL_INTERRUPT(); // enable external interrupt to receive more bytes
}
}
// error, should not occur -> go to safe state
else {
SwUART_state = IDLE;
}
}
ISR(INT0_vect) { // external interrupt handler
SwUART_state = RECEIVE;
DISABLE_EXTERNAL_INTERRUPT(); // disable external interrupt during data bits
DISABLE_TIMER_INTERRUPT(); // disable timer interrupt to change register
TCNT0 = 0; // clear counter
OCR0A = TICK_ONEANDHALF; // wait one and a half period
ENABLE_TIMER_INTERRUPT(); // enable timer again
}
void InitSwUART(void) {
TRXDDR |= (1 << TX_PIN); // set TX pin as output
TRXDDR &= ~(1 << RX_PIN); // set RX pin as input
// Timer0 init
TCCR0A |= (1 << WGM01); // CTC mode
TCCR0B |= (1 << CS01); // prescaler 8
TIMSK |= (1 << OCIE0A); // interrupt on compare
SET_TX_PIN(); // set TX-line to idle
// External interrupt
MCUCR |= (1 << ISC01); // interrupt on falling edge
ENABLE_EXTERNAL_INTERRUPT(); // turn external interrupt on
SwUART_state = IDLE; // set init state
}
void put_char(const unsigned char c) {
while(SwUART_state != IDLE) {} // don't send while busy receiving or transmitting
SwUART_state = TRANSMIT;
SwUART_TXData = c;
SwUART_TXBitCount = 0;
TCNT0 = 0; // clear counter
OCR0A = TICK_ONE; // tick one period
TIFR |= (1 << OCF0A); // clear flag
CLEAR_TX_PIN(); // clear TX-line... start of preamble
ENABLE_TIMER_INTERRUPT();
}
