PORTB and INT external interrupts stucks the code - microcontroller

I am working on a project with PIC16F877 (using MPLABX). I use RB0 pin external interrupt and RB4 pin portb interrupt to detect zero cross detection. I did everything correct, in proteus simulation everything was okey. Then I set up the circuit on breadboard, the LCD wasnt displaying the numbers (just the white dots). I thought the problem is the RB0 and PORTB interrupt. I wrote a simple code just includeshe PORTB interrupt and LCD and simulated. Everything is okey until the interrupt occures, when interrupt comes the code stops. I am new to PIC, this is the code I wrote:
/*
* File: lcd_deneme_16f877a.c
* Author: BATUHAN
*
* Created on 28 Aral?k 2022 Çar?amba, 13:52
*/
#include <xc.h>
#include <stdio.h>
#include <stdint.h>
#pragma config FOSC = XT // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = ON // Data EEPROM Memory Code Protection bit (Data EEPROM code-protected)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = ON // Flash Program Memory Code Protection bit (All program memory code-protected)
#define _XTAL_FREQ 4000000
void __interrupt() interrpt()
{
if(INTF)
{
uint8_t dummy = PORTB; // Read PORTB to end mismatch condition
INTF=0;
RD0=RD0^1;
}
if(RBIF==1 && RB4==1)
{
uint8_t dummy = PORTB; // Read PORTB to end mismatch condition
RBIF=0;
RD0=RD0^1;
}
}
void main(void)
{
TRISD=0X00;
PORTD=0X00;
TRISB=0b00010001;
PORTB=0X00;
INTCON=0b11011000; // GIE PEIE TMR0IE INTE RBIE TMR0IF INTF RBIF
OPTION_REGbits.nRBPU = 1;
INTEDG=1;
int V=0;
while(1)
{
V++;
__delay_ms(200);
}
return;
}
I tried the PORTB and RB0 interrupts separately and the problem still occurs.
What could be the problem. Thanks in advance

This is because your program stucks in interrupt routine due to the lack of proper handling of interrupts. You don't seem to handle the INT interrupt at all. For RB interrupt-on-change (IOC), you have to handle it sort of a little different and end the mismatch condition before clearing the flag. According to the PIC16F877A Datasheet this how the IOC works and must be handled:
Four of the PORTB pins, RB7:RB4, have an interrupt-on-change feature. Only pins configured as inputs can cause this interrupt to occur (i.e., any RB7:RB4 pin configured as an output is excluded from the interrupt-on-change comparison). The input pins (of RB7:RB4)are compared with the old value latched on the last read of PORTB. The “mismatch” outputs of RB7:RB4
are OR’ed together to generate the RB port change interrupt with flag bit RBIF (INTCON<0>). This interrupt can wake the device from Sleep. The user, in the Interrupt Service Routine, can clear the interrupt in the following manner:
a) Any read or write of PORTB. This will end the mismatch condition.
b) Clear flag bit RBIF.
A mismatch condition will continue to set flag bit RBIF. Reading PORTB will end the mismatch condition and allow flag bit RBIF to be cleared.
So your interrupt service code should look like the following:
void __interrupt() interrpt()
{
if(RBIF && RB4)
{
volatile uint8_t dummy = PORTB; // Read PORTB to end mismatch condition
RBIF=0;
RD1=RD1^1;
}
else if(INTIF) {
INTIF = 0;
RD0 = !RD0; // Toggle D0 for INT interrupt
}
}
A friendly reminder
The proteus simulation is ok for some cases. However the simulation runs in ideal conditions. That's why you may not get the same expected behaviour in the real world conditions compared to proteus' ideal simulation conditions.

void __interrupt() interrpt()
{
if(RBIF)
{
PORTB; // Read PORTB to end the mismatch condition
RBIF=0;
if(RB4)
RD1=RD1^1;
}
else if(INTF) {
INTF = 0;
RD0 = !RD0; // Toggle D0 for INT interrupt
}
}

Related

Arduino timer4 custom PWM issue

I made a nice code which generates fast PWM with 50% duty cycle and I can change the frequency with a potentiometer. It outputs straight and inverted channels with some dead time. I am using Arduino Micro aka ATmega32U4. The code is actually "Atmel" code. Code is working fine until I power Arduino Micro off and then on again.
I have programmed the code and registers so that the frequency is changeable from 10kHz to 100kHz. But after power on/off the frequency changes from 5kHz to 50kHz. After this has happened I have to program the board again using Arduino IDE, to make it work correctly. Again after power on/off it has changed. I am quite sure that one of the registers is overwritten by the "Arduino hardware abstraction layer" or however we should name it. I have not yet read out all the registers so I do not know which one is overwritten. I guess it's the prescaler.
How do I prevent this from happening? Should I write the register contents somewhere else? Or should I write it few times to be sure?
Why or how this is happening anyway?
Here's the code:
#define OSC1 5
#define OSC2 13
uint8_t read_reg1;
uint8_t read_reg2;
int pot, freq;
void setup() {
pinMode(OSC1, OUTPUT);
pinMode(OSC2, OUTPUT);
Serial.begin(9600);
cli(); // disable global interrupts
TCCR4A=0; // clear register
TCCR4B=0x06; // configure prescaler to 64 (CK = CLK / 64 = 1.5 MHz)
TCCR4C=0;
TCCR4D=0; // select Fast PWM operation (0 << WGM41)|(0 << WGM40)
PLLFRQ=(PLLFRQ&0xCF)|0x30; // select clock source and frequency
OCR4C=150; // select PWM frequency
OCR4A=150/2; // set duty cycle
DT4 = 0x55; // set dead times. DT = (1 / 48Mhz) * 0...15
// enable interrupt on timer4 overflow
TIMSK4|=(1 << TOIE4);
// This register write has to be after others. Otherwise the PWM generation will not work. I do not know why.
TCCR4A=0x42; // COM4A1..0 = 01, OC4A and !OC4A connected. PWM4A = 1 (activate channel A PWM output)
sei(); // enable global interrupts
}
void loop() {
//cli();
pot = analogRead(A0);
freq = map(pot, 0, 1023, 14, 166);
//sei();
/*
Serial.print("Pot value: ");
Serial.print(pot);
Serial.print("\tFreq value: ");
Serial.println(1500000/freq);
*/
}
ISR(TIMER4_OVF_vect){
OCR4C = freq;
OCR4A = freq / 2;
}
I am not sure exactly why you got different behavior right after programming, but the bootloader that the Arduino Micro uses (Caterina) does not perform a full reset after it runs, so changes that the bootloader made to the AVR's registers are often visible to the user's sketch.
I was able to fix the problem by removing the line that modifies PLLFRQ. Here is a simplified version of your code that always produces 3.31 kHz PWM:
void setup()
{
pinMode(5, OUTPUT);
pinMode(13, OUTPUT);
TCCR4A = 0;
TCCR4B = 0x06; // configure prescaler to 64 (CK = CLK / 64 = 1.5 MHz)
TCCR4C = 0;
TCCR4D = 0; // select Fast PWM operation (0 << WGM41)|(0 << WGM40)
OCR4C = 150; // select PWM frequency
OCR4A = 150 / 2; // set duty cycle
DT4 = 0x55; // set dead times. DT = (1 / 48Mhz) * 0...15
// This register write has to be after others.
// Otherwise the PWM generation will not work. I do not know why.
// COM4A1..0 = 01, OC4A and !OC4A connected.
// PWM4A = 1 (activate channel A PWM output)
TCCR4A = 0x42;
}
void loop()
{
}
It's not a great idea to mess with the PLL postscaler since it will probably affect every other Arduino library that uses timers, including the USB stack.

SPI not working on atmega328p

I'm trying to program an atmega328p, but the SPI bus isn't working. It's not sending any data over the bus.
My code is as follows:
#include <asf.h>
#include <stdio.h>
#include <main.h>
int main (void)
{
board_init();
SPI_MasterInit();
DDRD = (1<<DDD5);
while(1)
{
PORTB &= ~(1<<DDB2);
SPI_MasterTransmit(0xAB);
PORTB |= (1<<DDB2);
PORTD ^= (1<<DDD5);
}
}
void SPI_MasterInit(void)
{
/* Set MOSI and SCK output, all others input */
DDRB = (1<<5) || (1<<3) || (1<<2);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
}
I'm trying to send some random data over the bus (0xAB) to check if the bus works properly so I can add further code. In the while loop I also set a pin.
On my scope image I see no data being send on the SPI pin MOSI and the CLK pin is also not sending information. PB5 (the pin I'm inverting everytime I try to send data) is working and has a period of about 20 microseconds.
I'm programming the Atmega328p through an Atmel ICE. The programming interface is also through SPI, I read somewhere that this might be an issue. I'm not completely sure.
Does anyone know what might be the problem?
My first guess was not setting SS pin (PB2) as output. It may cause switching to the slave mode almost randomly. But it seems to be set as an output (it's not stated in comments).
But after closer look to this expression, it's obvious it's not set at all:
DDRB = (1<<5) || (1<<3) || (1<<2);
There is a huge difference between logical or || and bitwise or |.

'Keyboard' was not declared in this scope - Arduino coding

I'm writing a simple program for an Arduino that will take the input of 2 buttons and output simulated keys for 2 different functions to use in Clone Hero.
Arduino editor (both online and local versions) spit out
'Keyboard' was not declared in this scope
The offline editor asks if Keyboard.h is included... Which it obviously is.
Any ideas why?
// Keyboard - Version: Latest
#include <Keyboard.h>
//btnWhammy is the button to replace whammy bar function
//btnSP is the button to replace star power activation
//Set Clone Hero to register j for whammy and k for star power
//declaring constant integers for the pins on the Arduino
const int btnWhammy = 2;
const int btnSP = 13;
//Declaring integers for the state of the button press
int btnWhammyState = 0;
int btnSPState = 0;
void setup() {
//Initialisation of the pins as inputs
pinMode(btnWhammy, INPUT);
pinMode(btnSP, INPUT);
}
void loop() {
//Setting the button states to the read of the digital pin (LOW is off, HIGH is on)
btnWhammyState = digitalRead(btnWhammy);
btnSPState = digitalRead(btnSP);
//If the whammy button is pressed, send 'j' to the keyboard, wait 100ms then release all keys
if (btnWhammyState == HIGH) {
Keyboard.press('j');
delay(100);
Keyboard.releaseAll();
}
//If the Star Power button is pressed, send 'k' to the keyboard, wait 100ms then release all keys
if (btnSPState == HIGH) {
Keyboard.press('k');
delay(100);
Keyboard.releaseAll();
}
}
This is a classic mistake -- you are probably compiling for a non-Leonardo board, like a Uno. The Keyboard.h library is not included because it is not present for the board you are compiling with.
I took your code and compiled it for Leonardo -- no issues. For Uno, I get the same error as you...
keyboard key was not declared in this scope i found a very simple and working trick of this problem just go to your main file where you declare all other keys that you are facing not declare
#include <DigiKeyboard.h>
#define KEY_UP_ARROW 0x52
#define KEY_DOWN_ARROW 0x51
#define KEY_LEFT_ARROW 0x50
#define KEY_RIGHT_ARROW 0x4F
#define KEY_TAB 0x2B

Why does delay() cause my arduino to reset?

I am using an Arduino Uno, connected to a USB shield, a RFID shield(adafruit PN532), an LCD, EEPROM(24AA256) and a RTC module(DS1307). I will not post my code here because it is too large and it is separated in multiple files.
In my program, I realize that if my programs enters a certain functions, after entering function after function, if I use a delay() at the end of the function I am currently in, the arduino resets. An example of what I mean is below.
void a() { b(); }
void b() { c(); }
void c() { d(); }
void d()
{
lcd_string("Testing", 0x80);
delay(2000); <---- Arduino resets at the delay here
}
At first, I thought it was because my dynamic memory was at 80%, and when I compiled, they said the Arduino might have some stability issues. So I modified my code such that my dynamic memory is now 57%. Problem still exist.
I thought maybe the delay() function has some overflow or something, so I tried replacing the delay with the following code.
unsigned long timing;
timing = millis();
timing += 2000;
while(millis() < timing);
The Arduino still resets.
Next, I thought maybe because my arduino is connected to my PC, some serial pin might have been causing the reset, so I used an external Power to power up the arduino and disconnected the USB. The arduino still resets.
Next, I thought maybe Timer1 might have been crashing with the delay() function, although the delay function uses Timer0 so I disabled my Timer1 . The arduino still resets.
Is there any other possibilities that I am missing out? My program storage space is at 69% which I believe shouldn't be an issue.
Edit
Here is my code for Timer1 ISR
ISR(TIMER1_OVF_vect)
{
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 34286;// = (16*10^6) / (1*1024) - 1 (must be <65536)
TCCR1B |= (1 << CS12);
// enable timer compare interrupt
TIMSK1 |= (1 << TOIE1);
triggered = 1;
}
Any other interrupt of flags used are in the library header files.
I am using the following external libraries
USB Host shield library 2.0
Adafruit PN532 master
A little sample to come close to RAM corruption ...
#define MEM_PER_LEVEL 50
#define TRY_TO_SURVIVE 10
void KillMe(int level) {
byte dummy[MEM_PER_LEVEL];
for ( byte i = 0; i < MEM_PER_LEVEL; i++)
dummy[i]= i;
Serial.println(level);
delay(1000); // not sure why this would hurt more than others
if (level < TRY_TO_SURVIVE) KillMe(level+1);
for ( byte i = 0; i < MEM_PER_LEVEL; i++) {
if (dummy[i] != i) {
Serial.println(F("corruption happened"));
while(1) {} // HALT
}
}
if (level == 0)
Serial.println(F("survived"));
}
void setup() {
Serial.begin(9600);
KillMe(0);
}
void loop() { }
I had the same problem - wherever I put a delay in my setup function the Arduino would restart.
For me, the problem was an instance of SoftwareSerial with invalid pin numbers.
SoftwareSerial mySerial(30, 31);
Anyone else landing on this question should check their pin numbers are appropriate for the board they're targeting. Not sure why the crash only happens if a delay is called, would be interested if anyone has insight into this!

UDR register cleared before reading data

I am trying to simulate the uart using ATmega128. I have written this code in AVR STUDIO 4.
The PORTB0 is for used switch so that when it is pressed it is connected to 5v dc and it sends 'a' to uart1. at other times it is connected to ground. the reception of data is by interrupt.
Using debugger, when there is data in UDR1 and RXC1 is set, program jumps to ISR, and then UDR register is immediately cleared and nothing is retrieved. Can any one tell me why this happens?
Here is the code.
volatile unsigned char rxdata;
void uart_init(void)
{
UCSR1A = 0x00;
UCSR1B |= (1<<RXCIE1)|(1<<RXEN1)|(1<<TXEN1); //0b10011000;
UCSR1C |= (1<<7)|(1<<UCSZ11)|(UCSZ10); //0b10000110;
UBRR1H = 0;
UBRR1L = 103; //9600 baud rate
}
ISR(USART1_RX_vect)
{
rxdata = UDR1;
PORTC = rxdata;
}
void putch(char data)
{
while(!(UCSR1A & 0x20));
UDR1 = data;
}
And the main program is
void port_init(void)
{
DDRC = 0xFF;
}
int main(void)
{
port_init();
uart_init();
sei();
while(1)
{
if (PINB & 0x01){
putch('a');
}
}
}
I had this once. In my case, setting the breakpoint before the flag was evaluated in the code cleared it, because The AVR Studio "read" the flag (as I had the flag register open). Setting the breakpoint AFTER the line where the flag was read, helped. In your case, set the breakpoint on line PORTC = rxdata;
To get a better debug feeling, I read the flag into a variable right at the beginning of the ISR and set the breakpoint right after this.
It's been some years since this happened and I'm not even sure if this was really the case. So, maybe you can verify this ;)
I took a look at the AVR Studio 4 help section. Regarding known simulator issues with respect to UART functions it states:
The UART/USART UDR register can only be modified from the application. Input via stimuli files or by modifying the I/O view etc is not possible.

Resources