Hej.
Jag har problem med koden till min manchesterkod-sändare. Har suttit länge, länge nu med samma problem.
Beskrivning av koden:
Hela sändarkoden ligger i interrupt rutinen för TMR1. Sändaren kallas för task0. När sändaren är aktiv och sänder ett meddelande så sätts flaggan transmiter_is_busy = TRUE, vilket hindrar att vi ändrar på de bitar vi skall sända.
TMR1 interruptar var 889us, vilket är längden på varje sampel/bit som sänds. (skriver sampel eftersom i manchesterkod består ju en bit av två bitar/sampel
)
Jag ligger inte kvar i interruptrutinen under hela den tid som krävs för att sända ett meddelande, utan det i interruptrutinen tar runt 30us, sedan hoppar vi tillbaka till main().
I main har jag en ADC som läser av en potentiometer kontinuerligt och omvandlar ADC-värdet (0-1023) till 0-255. (blir 0-64
varför vet jag inte, men det är ett senare problem.)
Om det omvandlade värdet är mindre eller större än 30 så skickas två olika meddelanden (byte_to_send) ut.
byte_to_send som är 8 bitar manchesterkodas i manchester_encode() och vi får byte_to_send_encoded_temp som är 16 bitar och är det som egentligen sänds ut av sändaren i interruptrutinen.
Problemet är som följer: När jag i main() sätter ett värde på byte_to_send_encoded_temp direkt, utan att använda byte_to_send + manchester_encode(), så funkar allt prima. Jag får en stabil bild av meddelandet på oscilloskopet. MEN, när jag använder byte_to_send + manchester_encode(), så blir det inte alls bra. Bilden/bitarna på oscilloskopet ändrar sig med jämna mellanrum, precis som om att jag ändrar på byte_to_send_encoded_temp eller något. Startbitarna sänds bra hela tiden, men inte byte_to_send_encoded_temp.
Hmm. Om någon har en ide av vad det är som spökar, så vore jag tacksam för förslag. Kan vara vad som helst. Något som kanske är självklart, men som jag inte har tänkt på.
/ Jonas
Hela koden:
Kod: Markera allt
void setup_multitasking(void);
void interrupt(void);
void PWMInit(void);
void LCDInit(void);
void manchester_encode(void);
volatile enum State {StartSequence, Data, StopBit};
volatile enum State nextState = StartSequence;
volatile char counter444us = 0;
volatile char byte_to_send;
volatile signed char counter_in_transmitFkn = 3;
volatile char startBits = 0b1010;
volatile int byte_to_send_encoded_temp = 0x0000;
volatile unsigned int AD_value;
//(c)Shane Tolmie, http://www.microchipc.com/, distribute freely for non commercial use on the condition that you include this web link somewhere in your document.
//*****
//multitasking system handle multiple tasks with one microprocessor
#define TRUE 1
#define FALSE 0
//task counters used to tell when a task is ready to be executed
unsigned char task0_counter=0;
//Note: every variable referenced in both interrupt and main() must be declared volatile. You have been warned!
//this enables/disables a task
volatile unsigned char task0_enable=TRUE; // We set this to TRUE when we want to send something.
volatile unsigned char transmiter_is_busy = TRUE;
volatile unsigned char counter_30ms_isReady = TRUE;
void setup_multitasking(void){
/*We want to wait 2248 clock cycles, or 889us @ 10MHz (instructions are 1/4 speed of clock). Timer 1 interrupts when it gets to 0xFFFF or 65535.
#define TICKS_BETWEEN_INTERRUPTS 2248 // Gives 889us
#define INTERRUPT_OVERHEAD 19
#define TMR1RESET (0xFFFF-(TICKS_BETWEEN_INTERRUPTS-INTERRUPT_OVERHEAD))
#define TMR1RESET_HIGH TMR1RESET >> 8
#define TMR1RESET_LOW TMR1RESET & 0xFF
T1CON.TMR1CS = 0; // timer mode
T1CON.T1CKPS0 = 0;
T1CON.T1CKPS1 = 0; // prescaler
T1CON.TMR1ON = 0;
TMR1H=TMR1RESET_HIGH;
TMR1L=TMR1RESET_LOW;
T1CON.TMR1ON = 1;
PIR1.TMR1IF = 0; // clear TMR1IF
PIE1.TMR1IE = 1; // enable interrupts
INTCON.PEIE=1; // pheripheral enable interrupt. Uncomment this and PORTD.F3 no longer blink.
INTCON.GIE=1; // global enable interrupt
// INTCON = 0b11000000; // GIE PEIE TMR0IE INTE RBIE TMR0IF INTF RBIF
}
void LCDInit(void){
LCD_Init(&PORTB); // Initialize LCD connected to PORTB
LCD_Config(&PORTB, 2, 3, 1, 7, 6, 5, 4);
LCD_Cmd(LCD_CLEAR); // Clear display
LCD_Cmd(LCD_CURSOR_OFF); // Turn cursor off
}
void PWMInit(void){
TRISC = 0; // CCP1 (PortC.2 = Output)
PR2 = 65; // Set PWM Period for approximately 38KHz (37.9KHz)
CCPR1L = 33; // Set PWM Duty-Cycle to 50%
CCP1CON = 0b00001100; // Mode select = PWM + 2bit of dutycucle.
T2CON = 0b00000100; // Timer2 ON + 1:1 prescale
}
// Inparameter: byte_to_send
// Outparameter: byte_to_send_encoded_temp
// Denna tar 565.6us
void manchester_encode(void){
char i;
char bit;
char temp1;
// volatile int temp2; // volatile så att jag kan se var i watch wimdow. annars så optimerar komplilatorn bort den
for(i=0; i<8; i++){
// picks out bit nr. i from byte_to_send.
temp1 = (0b1<<i);
bit = temp1 & byte_to_send;
bit = bit >> i;
if(bit==1){
byte_to_send_encoded_temp = (0b01<<i*2) | byte_to_send_encoded_temp;
}
if(bit==0){
byte_to_send_encoded_temp = (0b10<<i*2) | byte_to_send_encoded_temp;
}
}
byte_to_send_encoded_temp = ~byte_to_send_encoded_temp; //inverterar alla bitar för att tramsmit() vill ha det så.
// (TRSISC=1 stänger av PWM o ger därmed en nolla.
}
void interrupt(void){
//one tick every 889us at 10Mhz
if(PIR1.TMR1IF == 1){
INTCON.T0IF = 0; // reset flag
//set up timer 1 again to interrupt 899us in future
PIR1.TMR1IF = 0;
T1CON.TMR1ON = 0;
TMR1H=TMR1RESET_HIGH;
TMR1L=TMR1RESET_LOW;
T1CON.TMR1ON = 1;
//....................... task0 is the transmitter .............................
task0_counter++; //counts times we enter interrupt. zeros at the end of transmission.
// if(time >= 30ms since we last transmitted a byte) then we can transmitt a new byte.
if(task0_counter >= 33){
counter_30ms_isReady = TRUE; // i.e we can send a new message after 30ms (reciver needs this "cool time").
}
if(task0_enable==TRUE && counter_30ms_isReady == TRUE){
transmiter_is_busy = TRUE; // this tells main() that transmitter is transmitting(we can not accept new byte)
switch(nextState){
case StartSequence:
TRISC.F2 = startBits >> counter_in_transmitFkn; //TRISC.F2 = 1 stänger av PWM, dvs vi får en nolla.
counter_in_transmitFkn--;
if(counter_in_transmitFkn < 0){
nextState = Data;
counter_in_transmitFkn = 15;
}
break;
case Data:
TRISC.F2 = byte_to_send_encoded_temp >> counter_in_transmitFkn;
counter_in_transmitFkn--;
if(counter_in_transmitFkn < 0){
nextState = StopBit;
}
break;
// Sends one sampel of zero, so that the reciever end gets right.
// OBS! not one bit i.e 01 or 10 is send, only one "sampel" 0!.
case StopBit:
TRISC.F2 = 1; //stänger av PWM, dvs vi får en nolla.
//we are finsihed we our transmission. The next byte cannot
//be sent until approx 30ms has passed.
//when task0_counter=33 approx. 30ms have passed and counter_30ms_isReady = TRUE.
counter_30ms_isReady = FALSE;
task0_counter=0;
transmiter_is_busy = FALSE;
nextState = StartSequence;
counter_in_transmitFkn = 3;
break;
}
}
//..........................task0 end...........................................
} // if(PIR1.TMR1IF == 1){
} //interrupt routine
void main(void){
char textInt[7];
char textChar[4];
volatile char value255Scaled;
char old_value255Scaled;
TRISC = 0; //outputs. PWM here
TRISD = 0; //outputs
LCDInit();
PWMInit();
setup_multitasking();
while(1) {
AD_value = ADC_Read(0); // Get results of AD conversion. A value from 0 to ca 1023.
// Scale our AD-result to 0 to 255 values, which confines within one byte.
value255Scaled = (AD_value * 255)/1023;
ByteToStr(value255Scaled, textChar);
LCD_Out(2,1, textChar);
// we can accept new byte if transmitter not busy.
if(transmiter_is_busy == FALSE){
task0_enable = FALSE;
if(value255Scaled > 30){
// byte_to_send_encoded_temp = ~0b1010101010101010; //allt funkar när man kör denna direkt,
//utan att köra manchester_encode().
byte_to_send = 0b00000000;
manchester_encode();
}
if(value255Scaled < 30){
// byte_to_send_encoded_temp = ~0b0110011001100110;
byte_to_send = 0b10101010;
manchester_encode();
}
task0_enable = TRUE;
}
}
}