cycling through leds - c

Please help me with this code, it is making me crazy. This is a very simple program with 8-bit timer, cycling through all 8 leds (one-by-one). Am using ATSTK600 board.
My timers are working well, I think there is some problem with the loops (when I debug this program using avr studio-gcc, I can see all the leds working as I want but when I transfer it on board...leds don't blink). Am going crazy with this type of behavior.
Here is my code:
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned int intrs, i, j = 0;
void enable_ports(void);
void delay(void);
extern void __vector_23 (void) __attribute__ ((interrupt));
void enable_ports()
{
DDRB = 0xff;
TCCR0B = 0x03;
TIMSK0 = 0x01;
//TIFR0 = 0x01;
TCNT0 = 0x00;
//OCR0A = 61;
intrs = 0;
}
void __vector_23 (void)
{
for(i = 0; i<=8; i++)
{
while(1)
{
intrs++;
if(intrs >= 61)
{
PORTB = (0xff<<i);
intrs = 0;
break;
}
}
}
PORTB = 0xff;
}
int main(void)
{
enable_ports();
sei();
while(1)
{
}
}

Your interrupt routine is flawed. intrs counts only the number of times the loop has executed, not the number of timer interrupts as its name suggests. 61 iterations of that loop will take very little time. You will see nothing perceivable without an oscilloscope.
The following may be closer to what you need:
void __vector_23 (void)
{
intrs++;
if(intrs > 60)
{
intrs = 0;
PORTB = (0xff<<i);
i++ ;
if(i == 8 )
{
i = 0 ;
PORTB = 0xff;
}
}
}
Although setting the compare register OCR0A to 61 as in your commented out code would avoid the need for the interrupt counter and reduce unnecessary software overhead.

Are you sure that the code downloaded to the board is not optimized?
Have you attached volatile attribute to the PORTB identifier?
Is there a way for you to slow down the code (outside the debugger)? Any chance it's running but fast that you don't see it?
Can you verify that your intended code is in fact running (outside the debugger)?

When interrupt occurs, handler very quickly counts 62*9 times and finally sets PORTB to 0x00, so leds do only very short flash which is not visible. You see it in sumulator just because it runs slower and do not emulate visual dimming effect of fast port switching. Program has a design flaw: it tries to do full blinking cycle in single interrupt. That's wrong--only a single step should be performed in interrupt call. So handler should look like this:
void __vector_23 (void)
{
intrs++;
if(intrs >= 61)
{
PORTB = (0xff<<i);
intrs = 0;
i++;
if(i>8) i = 0;
}
}
Try this.
There is guidelin on interrupts handlers: Interrupt handler should be as fast and short as possible. Do not perform complex tasks in interrupts (cycle loop is one of them, if you get cycle in interrupt, try to remove it). Do not wait or delay in interrupts.

If you're seeing the behaviour you want when debugging with avr studio-gcc, then that gives you some confidence that your program is "good" (for some sense of the word "good"). So it sounds as though you need to focus on a different area: what is the difference between your debug environment and your stand-alone download?
When doing a stand-alone download, do you know if your program is running at all?
Are the LEDs blinking, or turning on at all? You don't explicitly say in your question, but that question could be very relevant to the debugging process. Does it look like the right behaviour, running at a different speed? If so, then your program is probably not doing some sort of initialisation that the debugger was doing.
When doing a stand-alone download, is the program being compiled with different settings compared to the debug version? Perhaps compiler optimisation settings are changing your program's timing characteristics.
(Your question would be better if you gave more detail about what the stand-alone download is doing. In general, it is hard for someone to debug a remote system when they're given few or no details about what is happening. Do all/some of the LEDs turn on at all?)

Related

Why is my C program continuously run forever without the usage of loop?

I am testing my microcontroller PIC18f4550 with the following circuit on Proteus simulation software.
My objective is to turn the led on for one second and turn it off.
Following is my code:
#include <xc.h>
#define _XTAL_FREQ 8000000
void delay(int t);
void main(void)
{
TRISB = 0x00; // set Port B as output
LATB = 0x00; // set all 8 outputs on Port B to 0
delay(20);
LATB = 1b00000001; // set port B0 to 1
delay(20);
LATB = 1b00000000; // set port B0 to 0
}
void delay(int t)
{
for (int i=0; i<t ; i++)
{
__delay_ms(50); //using xc8 compiler internal delay function - it doesn't like it if delay is too big so it is used inside for loop
}
}
When the simulation is run, the LED keep blinking forever. I did not use any loop in my program and I only intend to turn the LED on for once. What is causing the LED to blink continuously?
[EDIT 1]
I found a solution to my problem. I simply added while(1){} at the end of my code to stop the PIC from going into infinite loop.
You are programming for a microcontrollers. They don't have an extensive OS. Most of the cases, your IDE hides the fact that your main is running in a loop (like Arduino IDE does), or exiting your program makes the microcontroller reset, and will just start the program again.
You labeled it "mplab" , if you check the documentation of it it states:
"The compiler inserts special code at the end of main() which is executed if this function ends, i.e., a return statement inside main() is executed, or code execution
reaches the main()’s terminating right brace. This special code causes execution to
jump to address 0, the Reset vector for all 8-bit PIC devices. This essentially performs
a software Reset. Note that the state of registers after a software Reset can be different
to that after a hardware Reset.
It is recommended that the main() function does not end."
The C runtime environment may call main() in an endless loop. This can happen deliberately like this:
/* some other stuff... */
for (;;) {
main();
}
Or it can happen because after the return of main() the next bytes in the program memory make the processor restart, for example because of an exception, or other code following the call.
You might like to use a simulator that shows the assembly level of your program to follow the flow of control.
Another option is to use your tools to disassemble the executable.
I suggest you to use the debugger (inside simulator) tool provided in MPLAB X IDE and look how single instructions are being executed. Check if microprocessor is not getting reset by any peripherals.

8051 two timers and Interrupts problem in c

I want to make two timer works at the same time but it seems not working at all
I wrote the code to blink led.
The led would blink when i used either one of the timer and interrupt
when I used them both, two ports for led are not working.
Was there any rule that can't use two interrupts or timers at the same time?
or just my mcu broken?
btw I am using AT89S52
coding by keil uVision5
and program with WLpro
Here is my code
#include <reg52.h>
sbit LED = P0 ^ 5;
sbit LED2 = P0 ^ 6;
int i = 0;
int y = 0;
int x = 0;
int count = 0;
void blink2()
interrupt 3
{
TH1=0x7d;
TL1=0xec;
y++;
if(y==100) {
if(i==1) {
LED=0;
x=0;
}
else {
LED=1;
x=1;
}
y=0;
}
}
void blink1()
interrupt 1
{
TH0=0xd8;
TL0=0xf0;
count++;
if(count==100) {
if(i==1) {
LED2=0;
i=0;
}
else {
LED2=1;
i=1;
}
count=0;
}
}
void main() {
TMOD = 0x11; // timer mode
TH0 = 0xd8;
TL0 = 0xf0;
TH1 = 0x7d;
TL1 = 0xec;
TR0 = 1;
TR1 = 1;
IE = 0x8a;
}
In blink2() you test the global variable i, but you never change it.
Note aside: blink1() manages LED2, while blink2() manages LED. Perhaps a more consistent naming would help, and the same applies to the variables i, x, y and count.
There is no restriction to use more than one interrupt concurrently, but when of them executes, the others are temporarily blocked. It is not your problem here, your code is fine; but if you want an interrupt be able to be interrupted in turn, for low latency, you must re-enable interrupts in the (relatively) "slow" handler.
Last suggestion: where you have "if (y==100)" and lately "y=0", if you move "y=0" just below "if (y==100)" readability improves.
All the rest seems ok, but I would double-check the setup of the timers; I don't have at hand the datasheet, may be there is a flag to clear in the interrupt handler (I can't remember). Given that you say that a single timer works, I suppose you know what to do, two timers should run without any problem.

I need to know why my interrupts are not working here

I am using stm8l - discovery and i have created a code for toggling a led for every 1 second using timer (TIM1) but this is not working properly. I am missing something here in my configuration
I could enter the interrupt function for the first time but after that it does not enter the interrupt function. Someone please look into and help me out
enter code here
#include <iostm8l.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "defs.h"
unsigned int count = 0;
#svlreg #interrupt void TIM1(void)
{
count += 1;
TIM1_SR1 &= ~(0x01);
}
main()
{
CLK_DIVR = 0x00; // Set the frequency to 16Mhz
CLK_PCKENR2 = 0x02; // clock for timer1
PC_DDR = 0x80; // direction output for led
PC_CR1 = 0x80; // fast push pull mode
PE_DDR = 0x80; // direction output for led
PE_CR1 = 0x80; // fast push pull mode
TIM1_PSCRH = 0x3e; //to create a frequency for 1000 hz
TIM1_PSCRL = 0x80; // so prescalar is 16000
TIM1_CR1 = 0x01;
TIM1_IER = 0x01;
_asm("rim\n");
while(1)
{
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}
}
}
The interrupt enters only one time but after that it does not enter. So variable "count" remains at value 1
You are using magic numbers for the bit masks instead of defined constants, so the code is pretty damn hard to read for you and me both. Change this so that the code ends up like for example
TIM1_SR1 &= ~TIM1_SR1_UIF;
Since this is a 8 bit MCU it is also absolutely essential that you u suffix all integer contants, or they will be of type signed int, which you don't want.
For example this code TIM1_SR1 &= ~(0x01); is equivalent to TIM1_SR1 &= -2. Very easy to write accidental subtle bugs this way. I recommend studying Implicit type promotion rules.
It is highly recommended to disassemble every ISR you write to see what machine code you actually end up with, and single step it through the debugger while watching the register as well. This particular register seems to ignore having 1 written to it, so you could probably just do TIM1_SR = TIM1_SR1_UIF;. Incorrectly cleared timer flags inside ISRs is one of the most common bugs in embedded systems.
Quoting the manual:
UIF: Update interrupt flag
– At overflow or underflow if UDIS = 0 in the TIM1_CR1 register
– When CNT is re-initialized by software using the UG bit in TIM1_EGR register, if URS = 0 and UDIS = 0 in the TIM1_CR1 register.
– When CNT is re-initialized by a trigger event (refer to the TIM1_SMCR register description), if URS = 0 and UDIS = 0 in the TIM1_CR1 register
Your code doesn't appear to do any of this, so it is pretty safe to assume the timer counter isn't reset.
Another problem is that count must be declared as volatile or otherwise the compiler might optimize out this code completely:
if (count == 1000)
{
PE_ODR ^= 0x80;
count = 0;
}

MPLAB infinite loop

I have 2 questions.
The first: I have a problem in the behavior of this code; when I run it in Proteus the program make flasher "repeat the code in the main function"
what should I do?
This is the code:
#include <p18f452.h>
#include <delays.h>
#include <io.h>
void main ()
{
TRISC=0x00;
PORTC=0xff;
Delay1KTCYx(900);
PORTC=0x00;
Delay1KTCYx(900);
while(1)
{
}
}
The second question: what is the proper delay function I can use? and how can I measure the delay time?
Is the watchdog disabled in simulation ? If it is enabled it will cause the repetition of the program.
Try adding this line after the includes.
#pragma config WDT = OFF
You only have code to generate one flash. Move the flash and delays into the loop:
for(;;)
{
PORTC = 0xff;
Delay1KTCYx(900);
PORTC = 0x00;
Delay1KTCYx(900);
}
Measuring roughly can be made manually by timing N flashes with a stopwatch. It's of course easier to use a measurement intrument (an oscilloscope is nice for this) if you have it.
Also, since your duty cycle is 50%, you can simplify the code:
PORTC = 0;
for (;;)
{
PORTC = ~PORTC;
Delay1KTCYx(900);
}
This uses bitwise not (~) to invert the bits of PORTC, which will make them toggle from one to zero and vice versa. Setting the entire port to 0 before the loop makes sure all pins are at a known state.

Volatile Keyword - MSP430

I'm trying to flash an LED on a TI MSP430 Launchpad board. I have two pieces of code. One works, while the other doesn't. The only difference is the inclusion of the volatile keyword in working version. Why is this keyword needed for the program to execute?
This code works...
void main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
// Configure Port Directions
P1DIR |= 0x01; // 0000 0001
volatile unsigned int i;
for(;;)
{
P1OUT ^= 0x01; // Set P1.0 LED on
for (i = 20000; i > 0; i--); // Delay
}
}
While this code does not...
void main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
// Configure Port Directions
P1DIR |= 0x01; // 0000 0001
unsigned int i;
for(;;)
{
P1OUT ^= 0x01; // Set P1.0 LED on
for (i = 20000; i > 0; i--); // Delay
}
}
Without volatile, the compiler has a lot more liberty in optimizing out code which it determines does nothing, as well as reordering memory access. Your delay loop is being optimized out when not using volatile.
Neither version is any good, future versions of the compiler may generate vastly different code.
Most MSP430 development tools provide the intrinsic functions __delay_cycles() intended to be used when you want to wait a specific number of cycles.
For example:
#include <intrinsics.h>
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
// Configure Port Directions
P1DIR |= 0x01; // 0000 0001
for(;;)
{
P1OUT ^= 0x01; // Set P1.0 LED on
__delay_cycles(40000);
}
}
Note that the code generated for this will execute at full processor speed. If you need a longer delay in a power-restricted environment, please consider using timers and put the processor in low-power mode.
If you add a NOP in your second version in the loop:
for (i = 20000; i > 0; i--) {
asm volatile("nop");
}
it should work as well. In both cases the volatile is needed to prevent optimization. In the first version, it prevents the compiler from completely removing the loop. In the second version With asm it tells the compiler to leave it where it is (so it's not moved to another location).
That being sad, both versions are not considered to be good style: Consider using a timer for exact busy delays. The loops will not do what you want, if the core frequency is changed.
In examining the assembly output of IAR compiler (V4.21.9 for MSP430F5438) the infinite loop is always compiled in, with or without the volatile keyword. (Up to Medium optimization setting.) So this may be a compiler dependency. For sure try compiling with optimizations off.
Where the volatile keyword is important is to tell the compiler not to count on a value and hence reread it. For instance, you could be reading an input buffer receiving an external character. The compiler needs to be told to keep reading, since the buffer is updated by something out of its scope of knowledge.
I prefer a solution that works on every compiler, call a function from another module that is not optimized or not optimized with the loop. Asm is a good example. a dummy function that just returns
dummy:
ret
...
void dummy ( unsigned int );
unsigned int ra;
for(ra=0;ra<10000;ra++) dummy(ra);
The compiler can unroll the loop some if it wants but will have to call dummy with the right arguments in the right order, you can use maximum optimization on the C code without worry.
if you don't declare it volatile, then a lot of the compiler will perform run time optimization, hence you may not pick up the changes

Resources