Configuration of the input capture functionality of PIC18F46K22 - c

I'am using a PIC18F46K22 to measure time that elapses between two event (rising edges of a square wave) using the input capture mode. I configured the related registers but I don't know because the code doesn't work; I'll show you a summary of my code. This is the part of code in the main function that configures the input capture:
//IC configuration
//Input Capture is RC1 (pin 12), TMR1 is used
TRISCbits.RC1 = 1;
CCPTMRS0bits.C2TSEL1 = 0;
CCPTMRS0bits.C2TSEL0 = 0;
PIE2bits.CCP2IE = 1;
PIR2bits.CCP2IF = 0;
//IC on every rising edge
CCP2CONbits.CCP2M3 = 0;
CCP2CONbits.CCP2M2 = 1;
CCP2CONbits.CCP2M1 = 0;
CCP2CONbits.CCP2M0 = 1;
And this is the ISR code:
void interrupt ISR(void) {
if(PIR2bits.CCP2IF) {
PIR2bits.CCP2IF = 0;
//code...
}
}
What's wrong or missing in the configuration?
Thanks!

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.

Seven Segment Display Scrolling

I am coding SSD display using 2 cascaded shift registers. I am using a mikroC for PIC compiler. I can display a static sequence of numbers upto 4 digits with my code Static Display of 4 Numbers
#define SHIFT_CLOCK PORTB.F1 //Clock Connection of 74HC595 SSD Driver
#define SHIFT_LATCH PORTB.F3 //Latch Connection of 74HC595 SSD Driver
#define SHIFT_DATA PORTB.F2 //Data Connection of 74HC595 SSD Driver
char array4[4] = {6, 91, 79, 102}; //Display 1234 on SSD
char digit[4] = {0xFE, 0xFD, 0xFB, 0xF7}; //Switch on the SSD digits one by one
char i,j,temp,flag1,flag2;
void InitTimer0()
{
OPTION_REG = 0x86;
TMR0 = 6;
INTCON = 0xA0;
}
void latch595()
{
SHIFT_LATCH = 1;
Delay_us(1);
SHIFT_LATCH = 0;
}
void shiftdata595(unsigned char _shiftdata)
{
int i;
unsigned char temp;
temp = _shiftdata;
i=8;
while (i>0)
{
if (temp.F7==0)
{
SHIFT_DATA = 0;
}
else
{
SHIFT_DATA = 1;
}
temp = temp<<1;
SHIFT_CLOCK = 1;
SHIFT_CLOCK = 0;
i--;
}
}
void Interrupt()
{
if (TMR0IF_bit)
{
TMR0IF_bit = 0;
TMR0 = 6;
flag1 = 1;
flag2 = 1;
}
}
void main()
{
TRISB = 0;
TRISC.F1 = 1;
InitTimer0();
while (1)
{
if (PORTC.F1==0)
{
if (flag2==1)
{
shiftdata595(digit[i]);
i++;
if(i==4)
{
i=0;
}
if (flag1==1)
{
shiftdata595(array4[j]);
latch595();
j++;
if (j==4)
{
j=0;
}
}
}
}
else if(PORTC.F1==1)
{
shiftdata595(0);
shiftdata595(0);
latch595();
}
}
}
If I add more digits to the array4[], say upto 9, I will need to scroll the digits to the left sequentially.
I tried shifting the array by
temp = array4[0];
for (n=1; n<8; n++)
{
array4[j-1] = array[j];
}
array[9] = temp;
I hoped that this code will left shift the array and the display will scroll, but all I am getting is a jumbled up display. If I add a delay, I can see that the numbers are getting displayed but without scrolling.
Is the basic algorithm faulty or can it be used by modifying the code?
I did figure out the problem with my code. The loop was wrong. I am using two 74HC595 in cascaded mode. One controls the digits(common cathode) and other controls the segments. Since there is only one data line that passes on the information to the digits as well as the segments, the timing of the digits advancement and the segments needs to be coordinated. The entire problem was that I was unnecessarily concentrating on the timing part which was coordinated but instead, I should have concentrated on the loop condition which advances the segments and then left shifts the array.
On friend pointed out that I need to write down the data values on a piece of paper for each loop and that solved the problem. Instead of feeding the loop the length of the array manually like array4[8] or array4[10], I used the sizeof() function and then after the first four iterations of the loop, left shifted the array one place. Now the scrolling works perfect.
Here is the updated and working code,
shiftdata595(array4[tmp7]);
latch595();
Delay_ms(32);
tmp7++;
if (tmp7>=4)
{
tmp7=0;
tmp1 = sizeof(array4)/sizeof(array4[0]);
tmp2 = array4[0];
for (n=1;n<tmp1;n++)
{
array4[n-1] = array4[n];
}
array4[tmp1-1] = tmp2;
}

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 - Reading Serial Data while performing for loop

I just got my arduino the other day. I am currently making a program in java to control my arduino using serial communication. So far, I only have the program turn it on or off. But I ran into an issue. I have my arduino fade two rgb leds, looping through every color. I run into my issue here. When I press the button to turn it off(java program), it doesn't turn off until its ran through every color(complete the for loops). I want it to instantly shut off. Is there any way I can read serial data in the for loops, or is there any possible way I can turn it off instantly, not having to wait for the for loops to complete? Here is the code:
const int redPins[] = {11,6};
const int greenPins[] = {10,5};
const int bluePins[] = {9, 3};
const int pinCountPerColor = 2;
const int sensorPin = 0;
int lightLevel;
int val = 0;
boolean isOn;
void setup() {
Serial.begin(9600);
setColourRgb(0,0,0);
isOn = true;
}
void loop() {
if(isOn) {
unsigned int rgbColour[3];
lightLevel = analogRead(sensorPin);
if(lightLevel >= 400) {
rgbColour[0] = 255;
rgbColour[1] = 0;
rgbColour[2] = 0;
for (int decColour = 0; decColour < 3; decColour += 1) {
int incColour = decColour == 2 ? 0 : decColour + 1;
for(int i = 0; i < 255; i += 1) {
lightLevel = analogRead(sensorPin);
if(lightLevel <= 400) {
setColourRgb(255, 255, 255);
} else {
rgbColour[decColour] -= 1;
rgbColour[incColour] += 1;
setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
delay(5);
}
}
}
} else {
setColourRgb(255, 255, 255);
}
}
}
void setColourRgb(unsigned int red, unsigned int green, unsigned int blue) {
for(int r = 0; r < pinCountPerColor; r++) {
analogWrite(redPins[r], red);
}
for(int g = 0; g < pinCountPerColor; g++) {
analogWrite(greenPins[g], green);
}
for(int b = 0; b < pinCountPerColor; b++) {
analogWrite(bluePins[b], blue);
}
}
void serialEvent()
{
while (Serial.available())
{
val = Serial.parseInt();
if(val == 1)
{
isOn = true;
//do nothing
}
else if(val == 0)
{
setColourRgb(255, 255, 255);
isOn = false;
}
}
Serial.println("Succesfully received.");
}
It is best to create a state machine for the colors, that does not have any blocking for loops, to dwell in. Especially loops with delays. So that each cycle through the loop changes the color and polls the Serial.
This is the art to writing real time code, or simply non-blocking code.
Note it is possible to create a timer interrupt to better schedule RGB updates. See Answer about Timer Interrupts to write precision updates.
#mpflaga answered your question correctly.
I would add that if you projects get bigger than just two leds fading, you might want to use something more reliable than a hand-made state machine.
That is called a Real Time Operating System (RTOS) and it allows you to have different threads running at different frequencies.
I personally use ChibiOS/RT for my robot project. There is a port for Arduino you can download here, it's very well documented and I'd say pretty easy to use once you get the basics. The nice thing to do is to add a higher level layer to manage the threads.
Here is a page with describing it and other solutions : Arduino rtoslibs
And here are some tutorials on real time and ChibiOS for Arduino:
It’s time for real-time
Blinking in real-time
ChibiOS for the Arduino IDE
Hope it helps! :)

Resources