USART med MPCM på en AVR

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
davrex
Inlägg: 149
Blev medlem: 18 januari 2009, 22:05:15

Re: USART med MPCM på en AVR

Inlägg av davrex »

Har nu kommit en bit på vägen... och stött på en irriterande fel nu igen.

Problemet nu är att jag via usb skickar in en adress där mastern kollar om den finns med i en array finns den inte det lägger den till den. Och lägger in vad för data som ska skickas till rs485 enheten i en "out[]" array som innehåller alla data som ska ut via rs485.

Sedan det main gör är att den tar en i taget ur listan med adresser och skickar iväg adressen och sedan tar datan från out och skickar den med. Och där efter svara slaven och då ska den datan läggas in i en array "sta[]". Och det är här problemet uppkommer att den lägger in resultatet från den första enheten till den enheten som är efter. Och det är tänkt att det ska funka med att söka efter adresser som inte nås det kan förekomma där av har jag försökt lägga till en timeout.

För mastern, Som nu också innehåller en USB del så klipper ut dom delana till uarten:

Kod: Markera allt

int main(void)
{
uchar   i;

    wdt_enable(WDTO_1S);
    odDebugInit();
    DDRD = ~(1 << 2);   /* all outputs except PD2 = INT0 */
    PORTD = 0;
    PORTB = 0;          /* no pullups on USB pins */
/* We fake an USB disconnect by pulling D+ and D- to 0 during reset. This is
 * necessary if we had a watchdog reset or brownout reset to notify the host
 * that it should re-enumerate the device. Otherwise the host's and device's
 * concept of the device-ID would be out of sync.
 */
    DDRB = ~USBMASK;    /* set all pins as outputs except USB */
    computeOutputStatus();  /* set output status before we do the delay */
    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
    i = 0;
    while(--i){         /* fake USB disconnect for > 500 ms */
        wdt_reset();
        _delay_ms(2);
    }
    usbDeviceConnect();
    TCCR0 = 5;          /* set prescaler to 1/1024 */
    usbInit();
    USART_Init();
    sei();
    usart_busy =0;
    for(;;){    /* main event loop */
        wdt_reset();
        usbPoll();
        if(TIFR & (1 << TOV0)){
            TIFR |= 1 << TOV0;  /* clear pending flag */
            timerInterrupt();
        }
    if(usart_busy == 0)
        USARTWriteChar(next_slave());
    else if(usart_busy != 1){
        if(usart_busy == 3000)
            usart_busy=0;
        else
            usart_busy++;
    }
	}
    return 0;
}
void USARTWriteChar(uint8_t addr)
{
   
   while ((UCSRA & (1 << UDRE)) == 0) {};
   usart_busy = 1;
   UCSRB |= (1<<TXB8);
   currentAddr = addr; 
   UDR=currentAddr;
 
   utDATA = out[currentAddr];
   
   
 }
ISR(USART_UDRE_vect)
{ 
    if(usart_busy == 1){
        UCSRB &= ~(1<<TXB8); 
        UDR = utDATA;
        usart_busy = 2;
   }
} 

ISR(USART_RXC_vect) 
{ 
   sta[currentAddr] = UDR;
   usart_busy = 0;
} 
void USART_Init() 
{ 
   UCSRC = (1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
   UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<UCSZ2)|(1<<UDRIE);   

   UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
   UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 
}
void add_slave(uint8_t i)
{
    slave[Cslave] = i;
    Cslave++;
}

int find_slave(uint8_t i)
{
    int n=0;
    while(n < Cslave){
        if(slave[n] == i)
            return 1;
        else
            n++;
    }
    return 0;
}
 
uint8_t next_slave(void)
{   
    int c =CheckSlave;
    CheckSlave++;
    if(CheckSlave > Cslave){
        c = 0;
        CheckSlave = 0;
    }
    return slave[c];

}

och hela koden i sin helhet:

Kod: Markera allt

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <stdlib.h>

#include "usbdrv/usbdrv.h"
#include "usbdrv/oddebug.h"
#include <util/delay.h>

#define EEPROM_LOCATION (void *)37

#define F_CPU 12000000
#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 

static uchar    actionTimers[8];

volatile uint8_t currentAddr;
volatile uint8_t utDATA; 
volatile uint8_t inDATA; 
volatile uint16_t usart_busy = 0; 

volatile uint8_t sta[100];
volatile uint8_t out[100];
volatile uint8_t slave[100];
volatile uint8_t Cslave = 0;
volatile uint8_t CheckSlave = 0;

uint8_t next_slave(void);
void USART_Init(void);
int find_slave(uint8_t);
void add_slave(uint8_t);
void USARTWriteChar(uint8_t);
void USART_Init(void); 


/* This is the AT90S2313 version of the routine. Change for others. */
static void outputByte(uchar b)
{
    PORTB = (PORTB & ~0xfc) | (b & 0xfc);
    PORTD = (PORTD & ~0x30) | ((b << 4) & 0x30);
}

static uchar    computeTemporaryChanges(void)
{
uchar   i, status = 0, mask = 1;

    for(i=0;i<8;i++){
        if(actionTimers[i])
            status |= mask;
        mask <<= 1;
    }
    return status;
}

static void computeOutputStatus(void)
{
uchar   status = eeprom_read_byte(EEPROM_LOCATION) ^ computeTemporaryChanges();

    outputByte(status);
}

/* We poll for the timer interrupt instead of declaring an interrupt handler
 * with global interrupts enabled. This saves recursion depth. Our timer does
 * not need high precision and does not run at a high rate anyway.
 */
static void timerInterrupt(void)
{
static uchar    prescaler;
uchar           i;

    if(!prescaler--){
        prescaler = 8;  /* rate = 12M / 1024 * 256 * 9 */
        for(i=0;i<8;i++){
            if(actionTimers[i])
                actionTimers[i]--;
        }
        computeOutputStatus();
    }
}

USB_PUBLIC uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;
uchar           status = eeprom_read_byte(EEPROM_LOCATION);
static uchar    replyBuf[2];

    usbMsgPtr = replyBuf;

    
    if(rq->bRequest == 0){  /* ECHO */
        replyBuf[0] = rq->wValue.bytes[0];
        replyBuf[1] = rq->wValue.bytes[1];
        return 2;
    }
    if(rq->bRequest == 1){  

        if(sta[rq->wValue.bytes[0]] == 0x00){
            if(find_slave(rq->wValue.bytes[0]) == 0){
                add_slave(rq->wValue.bytes[0]);
            }else{   
                
                replyBuf[0] = sta[rq->wValue.bytes[0]];
            }
        }else{
            replyBuf[0] = sta[rq->wValue.bytes[0]];
        }
        out[rq->wValue.bytes[0]]= rq->wIndex.bytes[0];
        return 2;
    }
      if(rq->bRequest == 4){  /* GET_STATUS -> result = 2 bytes */

        replyBuf[0] = status;
        replyBuf[1] = computeTemporaryChanges();
     

        return 2;
    }
    if(rq->bRequest == 2 || rq->bRequest == 3){ /* SWITCH_ON or SWITCH_OFF, index = bit number */
        
        uchar bit = rq->wIndex.bytes[0] & 7;
        uchar mask = 1 << bit;
        uchar needChange, isOn = status & mask;
        if(rq->bRequest == 2){  /* SWITCH_ON */
            status |= mask;
            needChange = !isOn;
        }else{              /* SWITCH_OFF */
            status &= ~mask;
            needChange = isOn;
        }
        if(rq->wValue.bytes[0] == 0){   /* duration == 0 -> permanent switch */
            actionTimers[bit] = 0;
            eeprom_write_byte(EEPROM_LOCATION, status);
        }else if(needChange){   /* temporary switch: value = duration in 200ms units */
            actionTimers[bit] = rq->wValue.bytes[0];
        }
        
    }
    computeOutputStatus();
    return 0;
}

/* allow some inter-device compatibility */
#if !defined TCCR0 && defined TCCR0B
#define TCCR0   TCCR0B
#endif
#if !defined TIFR && defined TIFR0
#define TIFR    TIFR0
#endif

int main(void)
{
uchar   i;

    wdt_enable(WDTO_1S);
    odDebugInit();
    DDRD = ~(1 << 2);   /* all outputs except PD2 = INT0 */
    PORTD = 0;
    PORTB = 0;          /* no pullups on USB pins */
/* We fake an USB disconnect by pulling D+ and D- to 0 during reset. This is
 * necessary if we had a watchdog reset or brownout reset to notify the host
 * that it should re-enumerate the device. Otherwise the host's and device's
 * concept of the device-ID would be out of sync.
 */
    DDRB = ~USBMASK;    /* set all pins as outputs except USB */
    computeOutputStatus();  /* set output status before we do the delay */
    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
    i = 0;
    while(--i){         /* fake USB disconnect for > 500 ms */
        wdt_reset();
        _delay_ms(2);
    }
    usbDeviceConnect();
    TCCR0 = 5;          /* set prescaler to 1/1024 */
    usbInit();
    USART_Init();
    sei();
    usart_busy =0;
    for(;;){    /* main event loop */
        wdt_reset();
        usbPoll();
        if(TIFR & (1 << TOV0)){
            TIFR |= 1 << TOV0;  /* clear pending flag */
            timerInterrupt();
        }
    if(usart_busy == 0)
        USARTWriteChar(next_slave());
    else if(usart_busy != 1){
        if(usart_busy == 30000)
            usart_busy=0;
        else
            usart_busy++;
    }
	}
    return 0;
}
void USARTWriteChar(uint8_t addr)
{
   
   while ((UCSRA & (1 << UDRE)) == 0) {};
   usart_busy = 1;
   UCSRB |= (1<<TXB8);
   currentAddr = addr; 
   UDR=currentAddr;
 
   utDATA = out[currentAddr];
   
   
 }
ISR(USART_UDRE_vect)
{ 
    if(usart_busy == 1){
        UCSRB &= ~(1<<TXB8); 
        UDR = utDATA;
        usart_busy = 2;
   }
} 

ISR(USART_RXC_vect) 
{ 
   sta[currentAddr] = UDR;
   usart_busy = 0;
} 
void USART_Init() 
{ 
   UCSRC = (1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
   UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<UCSZ2)|(1<<UDRIE);   

   UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
   UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 
}
void add_slave(uint8_t i)
{
    slave[Cslave] = i;
    Cslave++;
}

int find_slave(uint8_t i)
{
    int n=0;
    while(n < Cslave){
        if(slave[n] == i)
            return 1;
        else
            n++;
    }
    return 0;
}
 
uint8_t next_slave(void)
{   
    int c =CheckSlave;
    CheckSlave++;
    if(CheckSlave > Cslave){
        c = 0;
        CheckSlave = 0;
    }
    return slave[c];

}

Så här ser koden ut nu för slaven:

Kod: Markera allt

#include <avr/io.h> 
#include <avr/interrupt.h> 

#define F_CPU 12000000
#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 


/* usart globals */ 
volatile char rx_address = 0x02;
volatile char inDATA; 

int main (void) 
{ 
   DDRB = 0xFF;
   DDRC = 0x00;
   UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
   UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 

   UCSRC = (1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);
   UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<UCSZ2); 
   UCSRA |= (1<<MPCM); 
    sei();
    PORTB = 0xFF;
    PORTC = 0x00;
   for (;;) // Loop forever 
   { 
       
   }    
} 

ISR(USART_RXC_vect) 
{ 
 unsigned char status, control, inData; 
   status=UCSRA;    //Read register A 
   control=UCSRB;   //Read register B -- incl. RXB8 
   inData = UDR;    //Read data register      
   if(control & (1<<RXB8)) //Address frame? 
   { 
      if((inData) == rx_address)    //Verify address 
      { 
         UCSRA &= ~(1<<MPCM);//Disable MPCM filtering 
      } 
      else // not our address, ignore any data 
      { 
         UCSRA |= (1<<MPCM);//Enable MPCM filtering 
      } 
   } 
   else                   //Data Frame received 
   { 
        PORTB = inData; 
        
        UCSRA |= (1<<MPCM); //Enable MPCM 
        while ((UCSRA & (1 << UDRE)) == 0) {};
        if(inData == 0x01)
            UDR = 0x0A;
        else
            UDR = PINC;
   } 
} 

Skriv svar