Hello. I'm working on a project with Atmega8 and I'm switching the code from ASM to C (easier to me), and I have one doubt.
It should send 40times a value via UART when it reaches 1sec.
In assembly I used to work with Timer1 cause I needed fosc/PRE * seconds = 1MHz/256 *1sec= 3906 cycles.
Here is my ASM code:
Code:
Timer1_Init:
LDI R16,(1<<CS12)|(0<<CS11)|(0<<CS10) ;Prescaler 256
OUT TCCR1B,R16
LDI R16,(1<<TOIE1)
OUT TIMSK,R16
LDI R20, 0xF0 ; eTimer1 F0BE (FFFF-0F42) 3906 cicles 1 sec
LDI R21, 0xBE
OUT TR171H, R20
OUT TR171L,R21
Ret
Code:
int_overflow:
IN R1, SREG ; stack
ldi R16, (1<<TXEN) ; TXD UART enabled
out UCSRB, R16
LDI cnt,40 ; send 40 times our value
loop:
LDI R16, 0x38 ; send the value 8 ( HEX )
RCALL USART_Transmit
DEC cnt
BRNE loop
ldi R16, (0<<TXEN) ; turn off TXD UART
out UCSRB, R16
LDI R20, 0xF0 ; TIMER1 at F0BE for 3906 cycles (1 sec)(FFFF-0F42)
LDI R21, 0xBE
OUT TR171H, R20
OUT TR171L,R21
OUT SREG, R1 ; stack
reti
Switching this code to C I have some issues (Also all this code came from ATmega8 datasheet)
Code:
int TIMER_INIT()
{
unsigned int i;
/* Set TCNT1 to 0xF0BE */
TCNT1 = 0xF0BE; // for reach the 3906 cycles
/* Read TCNT1 into i */
i = TCNT1;
}
Code:
unsigned int TIM16_ReadTCNT1( void )
{
unsigned char sreg;
unsigned int i;
/* Save Global Interrupt Flag */
sreg = SREG;
/* Disable interrupts */
_CLI();
/* Read TCNT1 into i */
i = TCNT1;
/* Restore Global Interrupt Flag */
SREG = sreg;
return i;
}
void TIM16_WriteTCNT1( unsigned int i )
{
unsigned char sreg;
unsigned int i;
/* Save Global Interrupt Flag */
sreg = SREG;
/* Disable interrupts */
_CLI();
/* Set TCNT1 to i */
TCNT1 = i;
/* Restore Global Interrupt Flag */
SREG = sreg;
}
I don't know where to set the prescaler in C code ((1<<CS12)|(0<<CS11)|(0<<CS10)). Nor where to add the counter for send through UART my value 40 times. It should be something like :
Code:
for(i=0,i<40,i++){
uart transmit(value);
}
But as it's said before, I dont know where to place it.
Also what I thought was add a _delay_ms() that aproaches the timer. But I think may be "better" use this way.
In order to have a repeated interrupt every 1sec you can use timer1 CTC mode
Code:
// Timer1 output compare A interrupt service routine
ISR(TIMER1_COMPA_vect)
{
}
int main(void)
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
// Mode: CTC top=OCR1A
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: 1 s
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
TCNT1H = 0x00;
TCNT1L = 0x00;
ICR1H = 0x00;
ICR1L = 0x00;
OCR1AH = 0x3D;
OCR1AL = 0x08;
OCR1BH = 0x00;
OCR1BL = 0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK = (1 << OCIE1A);
while(1);
}
The transmit code can either be placed in the interrupt or you can use a flag variable set in the interrupt and execute the send code in main when the flag is set.
I'm not sure what were the timer read/write functions supposed to do, if they were just for the delay then you don't need any of them.
Thanks for the reply Alexan_e.
What I want to do is a communication between 2 ATmega (128 and 8) via RF modules, but it can be modeled as a simple wire.
I have a main base (ATmega128) and three bases (ATmega8). The main base must send a value (1,2,3) to select which base should transmit and then give back another signal for triangulate (the RF modules can take the RSSI, so with the power of the signal and ADC it's easy). So the main base should send a value for 125secs (or close to it) and then wait until the other micro receives, compares if it is the required value (1,2or3) and gives back another signal.
Main emits X during z seconds (thats the 40cnt in ASM code from above)
base1, base2 and base 3 compares with X (where X is the compare value)
wait until main stop emiting
base1 emits Y during z seconds
Main receives value Y and then change the emit value to change base.
Thats what it must do. But I'm stuck in how to emit during z secs and how to wait until the main base stops.
There is what it does in ASM code (TXD).
Ciclo Trabajo = duty Cicle
T.Subida = Rising