crash when clearing uint8_t on pic18f67k22 - c

I'm adding a clock to my program, but for some reason I cannot lower the value of my "sec" variable.
I have a millisecond timer that raises a flag every ms. So, every 1000 ms I clear the ms variable; this happens without a problem.
Now every 10 (for debug purposes) seconds I want to clear the sec variable and everything stops.
I'm using a pic18f67k22.
I should just be able to assign 0 to it, and it is VERY frustrating. Every value below 10 crashes; values above 10 resume like nothing happened.
minimal reproducible example, I left out lcd code as it was just for me to see if it still happened with minimal code, left out delay because it's just a bunch of "nop"'s, fuses and pin.h do not appear relevant either, fuses might be but your pins would be different):
main.c:
#include "fuses.h"
#include <stdbool.h>
#include <stdio.h>
#include <xc.h>
#include "clock.h"
#include "interrupt.h"
#include "LCDSerialTerminalMaster.h"
uint8_t prevSec = 0;
void main(void)
{
// disable comparators
CM1CONbits.CON = 0;
CM2CONbits.CON = 0;
CM3CONbits.CON = 0;
// disable analog input
ADCON0bits.ADON = false;
ANCON0 = 0;
ANCON1 = 0;
ANCON2 = 0;
INT_Init();
CLK_Init();
LCD_Init();
while(1)
{
if(CLK_GetSec() != prevSec)
{
prevSec = CLK_GetSec();
LCD_Write();
}
}
}
interrupt.c:
#include <stdbool.h>
#include "interrupt.h"
#include "clock.h"
#include "pin.h"
void INT_Init(void)
{
// Enable Interrupt Priority Vectors
IPEN = 1;
// RCI - high priority
UART1_RC_IP = 1;
UART2_RC_IP = 1;
UART1_TX_IP = 0;
UART2_TX_IP = 0;
MASTER_SYNC_IP = 1;
INT_Toggle(true);
}
void INT_Toggle(bool toggle)
{
INT_ToggleHigh(toggle);
INT_ToggleLow(toggle);
}
void INT_ToggleHigh(bool toggle)
{
INTCONbits.GIEH = toggle;
}
void INT_ToggleLow(bool toggle)
{
INTCONbits.GIEL = toggle;
}
void __interrupt() INT_InterruptManagerHigh(void)
{
if(PIR4bits.CCP4IF)
CLK_ISR();
}
clock.c
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <xc.h>
static uint8_t hour = 0;
static uint8_t min = 0;
static uint8_t sec = 0;
static volatile uint16_t ms = 0;
void CLK_Init(void)
{
T3CONbits.TMR3CS = 0b00; // Source = Fosc/4
T3CONbits.SOSCEN = 0b1; // SOSC disabled
T3CONbits.T3CKPS = 0b00; // Prescaler 1:1
CCP4CONbits.CCP4M = 0b1011; // Compare Mode: Special Event Trigger, reset TMR3 on CCP4 match
CCPTMRS1bits.C4TSEL = 0b01; // TMR3/TMR4
// set compare value to 5000
CCPR4L = 136;
CCPR4H = 19;
// Disable TMR3 interrupt.
PIE2bits.TMR3IE = 0;
// clear CCP4 interrupt.
PIR4bits.CCP4IF = 0;
// enable CCP4 interrupt.
PIE4bits.CCP4IE = 1;
IPR4bits.CCP4IP = 1;
// Start the Timer by writing to TMRxON bit.
T3CONbits.TMR3ON = 1;
}
void CLK_GetTime(char *buffer)
{
sprintf(buffer, "%02hhu:%02hhu:%02hhu", hour, min, sec);
}
uint8_t CLK_GetSec(void)
{
return sec;
}
void CLK_ISR(void)
{
PIR4bits.CCP4IF = 0;
ms++;
if(ms == 1000)
{
ms = 0;
sec++;
if(sec == 10)
{
sec = 0;
min++;
if(min == 60)
{
min = 0;
hour++;
if(hour == 24)
hour = 0;
}
}
}
}
the error happens in CLK_ISR, I can't assign a value lower than the value i'm comparing to, if I try sec-- the same thing happens.

Related

Is this the right way to interact with the button/joystick?

I am currently trying to create memory game with leds, but it becomes humiliating struggle. It would be more logical to start with idea. The idea is that with the help of two diodes some sequence is played and you have to repeat it with the joystick. My program should look something like this...
void main() {
generateNewGame();
blinkLeds();
for (uint8_t index = 0; i < Game_Length; index++) {
if(waitForPress() != GameArray[index])
blinkFail();
return;
}
}
blinkSuccess();
}
This two functions are working fine.
generateNewGame();
blinkLeds();
I have a problem with this function
waitForPress()
My "GameArray" is filled with ones and zeros.
I want to make it so that if I turn the joystick let's say to the left, then the function "waitForPress()" will return 1 and in the main i want to compare this 1 with my "GameArray", and if this is true, check the next element. Comparison with the "Game" array does not work for me. In addition, for some reason,my left led is constantly on, and the joystick does not respond. I hope my words make sense, I am ready to supplement the question if you have any questions.
My code at the moment
#define F_CPU 2000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
// Global
uint8_t Game[8];
int i;
const uint16_t n = 500;
void delay(uint16_t n) {
for(uint16_t i = 0; i < n ; i++) {
for(uint16_t j = 0; j < 200 ; j++) {
asm volatile ("NOP");
}
}
}
// Function for filling the game array with ones and zeros
void RandomNumber() {
srand((unsigned int)time(NULL));
for(unsigned int i = 0; i < sizeof(Game)/sizeof(Game[0]); i++) {
int v = rand() % 2;
Game[i] = v;
}
}
// Function for flashing the Game array sequence
void PlayDemo() {
int i;
for(i = 0; i <= 8; i++) {
if(Game[i] == 1) {
PORTA = 0x80;
delay(n);
PORTA = 0x00;
delay(n);
}
else if (Game[i] == 0) {
PORTA = 0x01;
delay(n);
PORTA = 0x00;
delay(n);
}
else {
PORTA = 0x00;
}
}
}
int waitForPress() {
uint8_t x = PINF;
// Until the button is off, do nothing
while(!(x & 0x20) && !(x & 0x08)) {
x = PINF;
}
// Check if we press to the left
if(x & 0x20) {
// Last LED ON
PORTA = 0x80;
// Wait ( Debouncing )
delay(n);
return 1;
}
// Check if we press to the right side
if(x & 0x08) {
// First LED ON
PORTA = 0x01;
// Wait ( Debouncing )
delay(n);
return 0;
}
return 0;
}
int main(void) {
MCUCR |= 0x80;
MCUCR |= 0x80;
DDRA = 0xFF;
PORTF = 0x20;
RandomNumber();
PlayDemo();
while(1)
{
// Check all elements of the "Game" array
for(uint8_t index = 0; index < 8; index++) {
// If the output of the function "waitForPress()" is not equal to "Game" array element
if(waitForPress() != Game[index]) {
// End the game
break;
} else if(waitForPress() == Game[index]) {
// Turn all led ON
PORTA = 0xFF;
// Wait
delay(n);
// Turn all led OFF
PORTA = 0x00;
// Wait
delay(n);
}
}
}
}
There might be multiple issues with your program:
(1) First of all: In the FOR-loop in which you are comparing the user input with your Game-Array, you are calling waitForPress() two times when the user entered the correct answer. This is not what you want, your code should look like this:
//...
if (waitForPress() != Game[index])
{
//...
break;
}
else
{
//... (correct answer)
}
//...
Or you could do:
//...
int userInput = waitForPress();
if (userInput != Game[index])
{
//...
break;
}
else
{
//... (correct answer)
}
//...
(2) Assuming the corrected code in (1), I think another main issue is the way you are processing the user input in general. Let me illustrate the problem:
Starting off, nothing is pressed. Your main program called waitForPress() and is "stuck" in the WHILE-loop, waiting for the user to push the joystick.
When the user finally pushes the joystick, the function returns 1 or 0.
In your main program, this return value is processed according to your IF-statements inside the FOR-loop (see (1)).
Shortly after this, waitForPress() is called again (in the case of a wrong input almost immediately; in the case of a correct input after your delays; I'm assuming this is meant to be something like a short "flash" of all LEDs lasting maybe a few hundred milliseconds).
Because the button is still pressed (humans are slow!), waitForPress() returns immediately. Now, your program thinks you made the same input again although you didn't even make a second input by your understanding.
To solve this, you want to detect a signal edge. The easiest way to do this is to make sure that the joystick is released before waiting until one button comes on. You may modify waitForPress() like:
int waitForPress() {
uint8_t x = PINF;
// Make sure that the user released the joystick
while((x & 0x20) || (x & 0x08)) {
x = PINF;
}
// Until one button comes on, do nothing
while(!(x & 0x20) && !(x & 0x08)) {
x = PINF;
}
//...
Additionally, you might want to add mechanisms for dealing with bouncing.
(3) You never exit the WHILE-loop in your main() function. Therefore, your program always remains in the state of expecting user input.
(4) In your function PlayDemo(), you are accessing a "non-existing" Game-array element (Game[8]) because the condition of your FOR-loop is i <= 8 and not i < 8.
Additionally, there might be hardware or hardware configuration problems. Such problems might be hard to find over StackOverflow because I don't have or know your exact setup. You could run test programs to check if your hardware is working fine.

Arduino the void loop() function isn't looping

I'm new to Arduino and I wrote the beginning a code that is supposed to play games read stories and more on an LCD display.
Here's my code
#include <LiquidCrystal.h>
// Arduino pins number
const int SW_pin = 2; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
const int LCD_RS = 7;
const int LCD_Enable = 8;
const int LCD_D4 = 9;
const int LCD_D5 = 10;
const int LCD_D6 = 11;
const int LCD_D7 = 12;
LiquidCrystal lcd(LCD_RS, LCD_Enable, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// Basic vars
int none = 0;
String Apps[2] = {"App selector","Credits"};
int CurrentApp = 0;
int Yaxis = 1;
int Xaxis = 1;
int HiCh = 0;
int button;
int JXaxis;
int JYaxis;
void Credits() { // CREDITS
Serial.print("- Credits app loading \n");
lcd.clear();
lcd.setCursor(3,0);
lcd.print("Credits app");
lcd.setCursor(0,1);
Serial.print("- Credits app loaded \n");
}
void setup() { // SETUP
Serial.begin(9600);
Serial.print("[2J");
Serial.print(" Serial Monitor opened \n \n");
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("App selector");
Serial.print("- App selector menu \n");
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, HIGH);
lcd.setCursor(0,1);
lcd.print(Apps[0]);
}
void SelectApp() { // SELECTAPP
switch (HiCh) {
case (1):
CurrentApp = 1;
Credits();
break;
default:
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Error");
Serial.print("- App loading error \n");
}
}
void loop() { // LOOP
while (none == 0) {
button = digitalRead(SW_pin);
int JYaxis = analogRead(Y_pin) / 128;
int JXaxis = analogRead(X_pin) / 128;
if (CurrentApp == 0) {
for (;;) {
if (button == 0) {
SelectApp();
}
if (JYaxis <= 1) {
if (HiCh != 0) {
HiCh = HiCh - 1;
delay(300);
}
}
if (JYaxis >= 7) {
HiCh = HiCh + 1;
delay(300);
}
}
}
}
}
I am only using one joystick as the controller and I have an Arduino UNO R3 board
I know a lot of other people have written about this and a lot of people have fixed the issue too but I cannot find the problem in my code...
I'm sure it's an error during the execution of the script that blocks the rest but I can't find where it is.
Thank you in advance!
If you need any specifications ask them to me and I'll try to answer them.
That code has a couple of issues.
In the loop() function you wouldn't normally make an infinite loop, you just put one run of your loop. That is, remove the while.
On the other hand, using delay() is not a great idea, as the processing loop will stop there and continue after specified time. The behavior you're trying to achieve is better implemented using timer interrupts.

Arduino: detecting buttons pressed inside a while loop

I have been trying to write a code to basically add points to a score whenever I pressed a button while a certain amount of time is running down. The problem I am finding is that it doesn't detect when the button is pressed while the time is decreasing, in fact it can only detect when the time starts to decrease and then it doesn't matter at which state the button is it will continue to add to the score. Anyway here is the main code:
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
score += 10;
Serial.println(score);
}
time--;
Serial.println(time);
}
}
}
And here is the full code if needed:
int button01 = 4;
int button02 = 3;
int button03 = 2;
int buttonState01 = 0;
int buttonState02 = 0;
int buttonState03 = 0;
float time;
int score;
void setup() {
score = 0;
time = 0;
pinMode(button01, INPUT);
pinMode(button02, INPUT);
pinMode(button03, INPUT);
Serial.begin(9600);
}
void loop() {
buttonState01 = digitalRead(button01);
buttonState02 = digitalRead(button02);
buttonState03 = digitalRead(button03);
if (buttonState01){
time = 3000;
while(time > 0){
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
}
}
You should read the status of a button inside the while loop. Like this:
while(time > 0)
{
buttonState02 = digitalRead(button02);
if (buttonState02){
Serial.println("Points");
}
time--;
Serial.println(time);
}
And in your code, there is no logic to add points to the score.
A hardware interrupt would do exactly what you need.
Attach an interrupt routine to the pin your button is linked to, and get it to set the 'score' variable. Make sure you introduce some sort of timeout to avoid button-bounce (I.e. set LastTimeIncremented when you increase the score, and only increment score if LastTimeIncremented is more than 1 second ago)
This way the score will always be set regardless of what else the program may be doing.
Information on this can be found in the Arduino https://www.arduino.cc/en/Reference/attachInterrupt
The example on that page would do exactly what you want, just replace 'blink' with 'incrementScore' and you're pretty much done
const byte ledPin = 13;
const byte interruptPin = 2;
int score = 0;
int increment = 1;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), incScore, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void incScore() {
score = score+increment;
// add anti-bounce functionality here
}

Arduino creating delay function

I am trying to make my own delay function. Briefly mydelay function is calling toggled function every secs seconds. The code is not well written, i know (this is the first version). But i am just trying to get it work properly. Then i will refactor it. But i have some unexpected bugs. First time the loop in x function is working properly. It is printing "I am in while" for 1 second and then it prints "Im ending mydelay" which is the behaviour i want. But after finishing the loop in x. The second time when it loops. It enters the mydelay function (that is ok). But then it is not printing "I am in while" at all. It just prints "Im ending mydelay" which is not good.
Here is the code:
#include <Arduino.h>
int led = 7;
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
}
void loop() {
x();
Serial.println("Im ending main loop");
}
void x() {
for (int i = 0; i <= 10; i++) {
mydelay(led, 0, 1);
mydelay(led, 1, 1);
}
}
void mydelay(int pin, int hol, int secs) {
int starttime = millis();
while ((millis() - starttime) <= (secs * 1000)) Serial.println("I am in while");
toggled(pin, hol);
Serial.println("Im ending mydelay");
}
void toggled(int pin, int hol) {
digitalWrite(led, hol);
}
Change int starttime = millis(); to unsigned long starttime = millis();. This might be the problem because if you are using an int, your program will go crazy after 32 seconds. That is a problem because an int can only hold a number going from -32,768 to 32,767 .
Also, you might as well try this:
while ((millis() - starttime) <= (secs * 1000))
{
Serial.println("I am in while");
}
maybe you can try to reset the millis using something like this, I don't have an arduino so it's not tested but hopefully it can help.
extern volatile unsigned long timer0_millis;
unsigned long reset = 0;
#include <Arduino.h>
int led = 7;
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
}
void loop(){
x();
Serial.println("Im ending main loop");
setMillis(reset);
}
void setMillis(unsigned long new_millis){
uint8_t oldSREG = SREG;
cli();
timer0_millis = new_millis;
SREG = oldSREG;
}
void x() {
for (int i = 0; i <= 10; i++) {
mydelay(led, 0, 1);
mydelay(led, 1, 1);
}
}
void mydelay(int pin, int hol, int secs) {
int starttime = millis();
while ((millis() - starttime) <= (secs * 1000)) Serial.println("I am in while");
toggled(pin, hol);
Serial.println("Im ending mydelay");
}
void toggled(int pin, int hol) {
digitalWrite(led, hol);
}

ATMega random number generation

For some context, I’m working on what is basically “Simon” for an Arduino project. I’m using an ATMEGA2560 and editing the code with Atmel Studio 6.1. The project uses the random number generator to create the sequence for the button input, which is where I’m running into trouble.
My current method of adding some variance is to use a timer interrupt to seed the random number, by incrementing a number to be processed through an equation. However, the timer simply doesn’t work – and the number doesn’t increment. Am I doing anything wrong with initialization, or is something else at fault?
Code:
#define F_CPU 1000000UL // 1 MHz, for timer
#include <avr/io.h> // normal stuff
#include <avr/interrupt.h> // timer interrupt
#include <util/delay.h> // easy delay functions
#include <stdlib.h> // random function
// global var that timer uses
volatile uint8_t count;
// function prototypes
int generateSeq(); // generates random number
int getRandomNumber(); // also generates random number (?)
int main(void)
{
// variables
int sequence[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // actual sequence
int terms = 0; // terms in sequence
int gameState = 0;
int ifWrong = 0; // if sequence is wrong
// timer interrupt (WHAT AM I DOING WRONG)
TCCR0A |= (1<<CS02)|(1<<CS00);
TIMSK0 |= (1<<TOIE0);
TCNT0 = 0;
count = 1;
sei();
while(1)
{
// actual "game" part
while(gameState == 1)
{
// generate term in sequence
// 1 = up, 2 = right, 3 = down, 4 = left
if(ifWrong == 0)
{
sequence[terms] = generateSeq(); // call sequence function
terms++;
}
}
}
}
// random seed for sequence generator (something wrong here?)
ISR(TIMER0_OVF_vect)
{
count++;
if(count >= 255)
{
count = 1;
}
}
int generateSeq() // function to generate sequence
{
// equation is currently a placeholder
int r2 = (int)rand() * (int)count;
int num = r2 * count;
return (num % 4) + 1;
}
gameState is 0, and never changed, so none of the generateSeq() code is called.
You also have a serious problem with sequence[terms] in that you don't check if terms is between 0 and 7. You will run off the end of the array.

Resources