I have written simple timer program for Atmega328 in normal mode. But I am unable to flash the LED if I compile the code in Atmel Studio 6.2. But same code works perfect if I compile in arduino IDE. I have given the code for Arduino as well as Atmel Studio below. There seems to be small issue somewhere. Is there any issue with F_CPU value?
// Code compiled using Atmel Studio:
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000
unsigned char x=0;
ISR(TIMER1_OVF_vect) {
x=!x;
}
void setup() {
DDRB=0x01;
TIMSK1=0x01; // enabled global and timer overflow interrupt;
TCCR1A = 0x00; // normal operation page 148 (mode0);
TCNT1=0x0000; // 16bit counter register
TCCR1B = 0x04; // start timer/ set clock
};
int main (void)
{
setup();
while(1)
{
PORTB= x;
}
return(0);
}
Code written with Arduino IDE:
#define LED 8
boolean x=false;
ISR(TIMER1_OVF_vect) {
x=!x;
}
void setup() {
pinMode(LED, OUTPUT);
TIMSK1=0x01; // enabled global and timer overflow interrupt;
TCCR1A = 0x00; // normal operation page 148 (mode0);
TCNT1=0x0000; // 16bit counter register
TCCR1B = 0x04; // start timer/ set clock
};
void loop() {
PORTB= x;
}
When working with interrupts, you need to enable both the global interrupts (in the timer register) and the local interrupts (in the status registers) in order for interrupt vectors to trigger.
This can be done by calling sei() (set enable interrupts) when you are ready to receive local interrupts. Typically you want to do this after you set up the global interrupts, near the end of you setup method.
I suspect that the interrupts are automatically enabled when working with the Arduino IDE.
Related
I am learning embedded and I had the simple task of lighting up a led, but also i want to implement a timer that turns the led on for a second and then turns it off for another seconds(and so on), but i am not sure how to do it. I am working on a ATmega324PB microcontroller using the IAR Embedded Workbench. Here is my code:
include "iom324pb.h"
#include <ioavr.h>
#include <intrinsics.h>
void set_output(int pin)
{
DDRC |=(1<< pin);
}
void set_pin(int pin)
{
PORTC |=(1 << pin);
}
void turn_off(int pin)
{
PORTC &= ~(1 << pin);
}
int main(void)
{
set_output(7);
while (1)
{
set_pin(7);
turn_off(7);
}
}
I have searched on the internet but the codes I've found were far too complex for my understanding.I've also tried using the __delay_cycles(1000); function but it doesn't do anything.
ATmega324PB has an internal 8MHz RC oscillator, while the code has no explicit initial process for the peripheral of MCU. Then, assuming ATmega324PB runs with a main clock of 8MHz by default, so a __delay_cycles(1000); would wait for about 125uS and some more. Instead, __delay_cycles(8000000); or a finite-loop, e.g. for(i=2000000;i>0;i--);, might work.
Suggestion: Try to use its internal Timer to implement the functionality of delay. The application note AVR130: Using the timers on tinyAVR and megaAVR devices would be a viable reference.
I am using atmega328P , as it shown in the attached picture
when the interruption is executed , the program doesn't turn back to the main to execute the rest of the program ?
i made 2 functions ; one to blink led in portC and the other in PORT D
the Led in PORT D (interruption) is working fine but the Led for PORT C in the main is not executed
is there a problem ??
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ACK 0x01
void portc_led(void)
{
PORTC|=(1<<5);
_delay_ms(100);
PORTC=(0<<5) ;
_delay_ms(100);
PORTC|=(1<<5);
_delay_ms(100);
PORTC=(0<<5) ;
_delay_ms(100);
}
void portd_led(void)
{
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
PORTD|=(1<<7);
_delay_ms(1000);
PORTD=(0<<7) ;
_delay_ms(100);
}
int main(void)
{
DDRB |= (1<<2)|(1<<3)|(1<<5); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<4); // MISO as input
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPIE); // Enable SPI Interrupt
SPCR |= (1<<SPE); // Enable SPI
DDRC= 0xFF ; // set PORT C as output
DDRD = 0xFF ;
sei();
spi_send_data(ACK);
portc_led();
}
ISR(SPI_STC_vect)
{
portd_led();
}
first of all your code will have a compile Error! because you don't provide a reference to spi_send_data function
but let us imagine that you include it above this piece of code
analyse your code
you say that
interruption is executed , the program doesn't turn back to the main
the program execution path definitely will ruturn to main routine... where will it go ?! :)
the code will execut the portc_led function one time (and only one time) maybe before interrupt or maybe after interrupt or maybe interrupt happen in between the function ...
so maybe portc_led alredy excuted happen befor interupt but you did not see it becuse it executed in only 400 ms !! and after finsh interupting nothing to do just wait for other interupt ! ..
simple solution : try to change the 100ms delay in portc_led to bigger delay and you will see ...
little advices for improve practicing techniques
look at this code PORTB=(0<<5) equivalent to portB=0b00000000 when you try to clear single bit in register you clear all register's bits ! which is not good ...use this code PORTB&=~(1<<5) for clear single bit which make bitwaise & between portc and 0b11101111 only change single bit and keep other bits as it is
always in interrupt routine make it small as much as you can ... just raise a flags and handle it in the main loop ... read more way you should make it small routine
your program dose not have a mian loop !! (sometimes called super loop)..
this loop is simply an infinity loop come after initalization of your systerm and run over and over ... some compiler add empty infinity loop at the end of main routine and other compiler dose not add ... it's a good practice to have a main loop in the main routine even if you not use it ! To keep your program alive
modify the code
not that the following code will not excute blancking in parallel (simultaneously) it will excute them in series (not simultaneously).. if you like to have a parallel blanking use timer interupt in portc_led insted of delay /or use an RTOS (a little bit advanced topic)
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ACK 0x01
volatile char spi_interupt_flag = 0;
void portd_led(void)
{
// this will blank led in pd7 for 3 sec
for(char i=0;i<6;i++){
PORTD^=(1<<PD7) ; // toggle pd7
_delay_ms(500); // you will see 500 ms blank
}
}
int main(void)
{
DDRB |= (1<<2)|(1<<3)|(1<<5); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<4); // MISO as input
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPIE); // Enable SPI Interrupt
SPCR |= (1<<SPE); // Enable SPI
DDRC= 0xFF ; // set PORT C as output
DDRD = 0xFF ;
sei();
spi_send_data(ACK); // this code will make compile error if you not provide a source for implementation
while(1){
if (spi_interupt_flag)
{
//this code only execute when data received from SPI
portd_led(); //do whatever you want to do for handle it
spi_interupt_flag = 0; //reset the flag again
}
PORTC^=(1<<PC5); //toggle pc5 for ever
_delay_ms(1000); // pc5 will toggle every 1 sec unless ther is interupt
}
}
ISR(SPI_STC_vect)
{
// just set a flag for handle interrupt in main
spi_interupt_flag = 1;
}
You have two conceptional errors in your code:
As long as the interrupt service routine is running, the main function can not run.
After portc_led(), the main() functions returns. Depending on the runtime environment of your compiler system (presumably some GCC) it finally runs in an endless loop, doing nothing. Only the interrupts keep triggering.
I am developing a simple program to run a buzzer in AVR on a Teensy 2.0 (ATMEGA32u4) and I am having great difficulty getting the PWM output to work. The PWM output is on PB6 and I can test it digitally so I am not worried about the hardware setup of the buzzer.
Eventually, the PWM will have a 50% duty cycle and the frequency will modulate, however, I am more concerned I am not getting any output at this point.
I have tried several different PWM setups and even have a second timer running to complete other tasks.
Here is my setup and program skeleton:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void button_handler(void);
void setup(void)
{
cli(); // Disable interrupts
// Set sysclk to 16 MHz
CLKPR = (1<<CLKPCE); // Prescaler change enable
CLKPR = 0x00; // Set prescaler to zero
DDRB = (1<<DDB6); // configure PORT B6 (buzzer) as output
// initliase timer1
// Fast PWM, TOP = OCR1A, Update OCR1B at TOP, TOV1 flag set on TOP
// Clear OC1B on compare match, set OC1B at TOP
// clkI/O/1 (No prescaling)
TCCR1A = (1<<COM1B1)|(1<<WGM11)|(1<<WGM10);
TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS10);
OCR1A = 1023; // Setup PWM Registers
OCR1B = 511; // 50% duty cycle
sei(); // Enable interrupts
}
int main(void)
{
setup(); // initialise device
for (;;)
{
// runs led blinking on PORTD, removed for simplicity
}
}
Really struggling to see where I am going wrong so any help would be much appreciated!
Finally managed a fix coming back after a few months, a simple clean fixed the issue.
for 4 days now, I am struggling to set up External interrupt on my STM32 and I have gone through tons of reading and other people's code to get it. But no luck.
I have two buttons and when pressing either one of them I expect to light up an LED, this example is only to get it working, I wanted to have something functional before proceeding and building rest of the code.
I am sorry if the code is a little messy, but I am working on neating my coding skills.
I've gone through manuals and datasheets but nothing seems to help.
Here is my main.c
#include "stm32l1xx_hal.h"
#include "buttons.h"
static void MX_GPIO_Init(void);
bool RightButtonFlag = 0;
bool LeftButtonFlag = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
controls_Interrupt_Init();
MX_GPIO_Init();
while (1)
{
if(RightButtonFlag){
Blue_ON();
}
if(LeftButtonFlag){
Green_ON();
}
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
{
Followed by part of stm32l1xx_it.c
#include "stm32l1xx_hal.h"
#include "stm32l1xx.h"
#include "stm32l1xx_it.h"
#include "buttons.h"
extern volatile uint8_t RightButtonFlag;
extern volatile uint8_t RightButtonFlag;
void EXTI15_10_IRQHandler(void)
{
if(GPIOC->IDR & GPIO_IDR_IDR_10){
RightButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR10;
}
if(GPIOC->IDR & GPIO_IDR_IDR_11){
LeftButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR11;
}
}
buttons.c
void controls_Interrupt_Init(void){
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable System Configuration Register */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI11_PC; /* Set up External Interrupt for Pin 11 Port C */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI10_PC; /* Set up External Interrupt for Pin 10 Port C */
EXTI->IMR |= EXTI_IMR_MR11;
EXTI->IMR |= EXTI_IMR_MR10;
EXTI->FTSR |= EXTI_FTSR_TR11; /* Falling trigger Selection Reg. Trigger 11 */
EXTI->FTSR |= EXTI_FTSR_TR10; /* Falling trigger Selection Reg. Trigger 10 */
NVIC_SetPriority(EXTI15_10_IRQn,1); /* Set Interrupt priority for pins 10-15 */
NVIC_EnableIRQ(EXTI15_10_IRQn); /* Enable NVIC for Pins Between 10-15 */
}
and buttons.h
void controls_Interrupt_Init(void);
#define Blue_ON() (HAL_GPIO_WritePin(BLUE_LED_PORT, BLUE_LED_PIN, 1))
#define Green_ON() (HAL_GPIO_WritePin(GREEN_LED_PORT, GREEN_LED_PIN, 1))
I am fairly new to coding and with my poor experience I expect to have screwed up something very simple.
You have to declare the flags as volatile. That's a hint to the compiler that the variable can change any time, independent of the normal program flow.
volatile bool RightButtonFlag = 0;
volatile bool LeftButtonFlag = 0;
When there is no volatile there, the compiler can assume that the flags never change in the main loop, and optimize it that way, that the variables will be loaded only once, before the loop.
Declaring them volatile only in the scope of the interrupt handler does no good, because the optimization will still take place in main(), where the volatile declaration is not visible.
It is good practice to move the declaration to a header file, and include that header everywhere the variable is referenced. Then the compiler can check that the types are indeed compatible.
UPDATE
The interrupt handler makes little sense. You set EXTI to detect a falling edge, then check if the input is high. Checking the GPIO data register is not reliable anyway, due to the bouncing effect of mechanical buttons.
You should rather check EXTI->PR in the handler, and reset the pending bit with a simple assignment instead of |=, otherwise you could accidentally clear another pending bit too.
void EXTI15_10_IRQHandler(void)
{
if(EXTI->PR & EXTI_PR_PR10){
RightButtonFlag = 1;
EXTI->PR = EXTI_PR_PR10;
}
if(EXTI->PR & EXTI_PR_11){
LeftButtonFlag = 1;
EXTI->PR = EXTI_PR_PR11;
}
}
You can still check somewhere if GPIOC->IDR actually reflects the button state, to eliminate possible hardware problems.
You can also try setting EXTI->SWIER from the debugger, or in the code, to simulate a button press.
It works now!!
In the process of cropping the code to post here, it seems I removed the logical error that was making my pin bounce back. My Bad... here's the code for your reference:-
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define F_CPU 1000000UL
ISR (INT1_vect)
{
ext_int1();
}
int ext_int1(void)
{
PORTD|=(1<<PD5);
}
int main(void) {
DDRD=0xF0;
PORTD=0xFF;
PORTD&=~(1<<PD5);
uint16_t a=0;
GICR|=(1<<INT1); // enable external interrupt INT1
sei();
while(1){
a=1;
a=2;
}
}
The previous problem is as below, thanks everyone for your patience & help.
I have a problem in Atmel ATMEGA8 while using external Interrupt INT1. The interrupt is set to when INT1 is LOW. Calling the interrupt is supposed to turn ON a pin PD6.
Now the problem is that if I declare PD6 as LOW, the pin reverts to LOW state when the interrupt condition is removed. But if I do not declare PD6, then the program works fine.
The code is as below:-
ISR INT1_vect()
{
PORTD|=(1<<PD6);
}
int main (void)
{
DDRD=0xF0;
PORTD|=(1<<PD3); // enabling pull up resistor for INT1
PORTD&=~(1<<PD6); // initialise PD6 to LOW
GICR|=(1<<INT1);
sei();
.
.
.
I have used other Interrupts for PWM (compare & over flow) & ADC (conversion complete) and they are working fine. I use PWM interrupts to run the PWM on digital output ports.
What happens can be summed up below:-
INT1 PD6
Open LOW
GND HIGH
Open LOW (if initialised in main())
Pin 6 on PORTD should not go low again unless you are setting it low somewhere else.
If you are not setting it low anywhere except at the start of main(), then that indicates that the system is resetting itself and running main() again. An enabled interrupt without a handler could cause that. Check to make sure the system is not crashing.