I've recently finished code for a PIC18F252 which uses the built in ADC to convert analogue inputs from 3 sensors into digital outputs that can be sent to motors. The code builds and uploads to the PIC perfectly fine, but unfortunately just doesn't work, and I'm struggling to see where the issue is.
After testing the output ports for the motors, I've found that they are all outputting the same signal, when they shouldn't be, and it doesn't change depending on the sensors.
My first thought is that there's something wrong between the output of the ADC (loading the result from ADRESH), and the if statements used to assign a digital value to these outputs.
I can't upload the entire code as this is coursework, but I've added the relevant parts. I've only included my function for AD conversion using one channel, but the functions for the other two channels are the same, just changing variables.
If anyone is able to spot an issue with this code (presumably around the if statements) I would be grateful!
#include <p18F252.h> // PIC specific definitions
#include <xc.h> // Xc8 compiler specifics
#include <stdio.h> // Standard C I/O library
#include <stdlib.h> // Standard C library
// Function declarations
void Config_ADC(void);
void delay(void);
void Motor_Output(unsigned char x, unsigned char y, unsigned char z);
void channel3(void);
unsigned char leftSens = 0b00000000; //Initialise left sensor variable
void Config_ADC(void){
// ADC Setup
TRISA = 0xFF; // configure port A as inputs
ADCON1bits.ADFM =0; // left justified
ADCON1bits.PCFG3=0;
ADCON1bits.PCFG2=1;
ADCON1bits.PCFG1=0;
ADCON1bits.PCFG0=0;
ADCON1bits.ADCS2=0;
ADCON0bits.ADCS1=1;
ADCON0bits.ADCS0=0;
ADCON0bits.ADON =1;
}
// Function for a delay of 1ms
void delay(void){
T2CON = 0x49; // start counting from 73
PR2 = 0x7C; // stop count at 124
T2CONbits.TMR2ON = 1; // activate timer 2
while(!PIR1bits.TMR2IF); // wait for timer flag
T2CONbits.TMR2ON = 0; // stop timer 2
PIR1bits.TMR2IF = 0; // clear flag
}
void channel3(void){
ADCON0bits.CHS2 = 0; //Channel selection
ADCON0bits.CHS1 = 1;
ADCON0bits.CHS0 = 1;
delay(); // Acquisition time to charge hold capacitor
ADCON0bits.GO_DONE = 1; // Start Conversion
while(ADCON0bits.GO_DONE); // Wait for A/D Conversion to complete
leftSens = ADRESH; // Return result
}
void main(void){
TRISB = 0x00; // configure Port B as output
Config_ADC(); // load ADC
while(1) { //loop forever/
channel3(); // Call channel 3 conversion
Motor_Output(leftSens, middleSens, rightSens);
}
}
// Function to send instructions to motors
void Motor_Output(unsigned char x, unsigned char y, unsigned char z){
int left, middle, right;
if(x >= 173){left = 1;} //173 chosen as threshold 8 bit value
else if(x < 173){left = 0;}
else if(y >= 173){middle = 1;}
else if(y < 173){middle = 0;}
else if(z >= 173){right = 1;}
else if(z < 173){right = 0;}
unsigned char output;
output = (left << 2) | (middle << 1) | right; //Bit shifted variables into one value
switch(output){
case 0x0:
PORTBbits.RB7 = 0; //Test for each output and activate motors accordingly
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x1:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 1;
PORTBbits.RB4 = 0;
case 0x2:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x3:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 1;
PORTBbits.RB4 = 0;
case 0x4:
PORTBbits.RB7 = 1;
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x5:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x6:
PORTBbits.RB7 = 1;
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x7:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
}
return;
}
Without going any deeper in analysis there are two major problems:
The if-else if-chain will do just one assigment to left. To make that obvious I have indented your source this way without any other changes:
if (x >= 173) { // Either THIS...
left = 1;
} else
if (x < 173) { // Or THAT will be true.
left = 0;
} else // None of the following is executed therefore.
if (y >= 173) {
middle = 1;
} else
if (y < 173) {
middle = 0;
} else
if (z >= 173) {
right = 1;
} else
if (z < 173) {
right = 0;
}
So middle and right will have undefined values.
All your cases in the switch are missing a break. So only the last case or none at all will be executed. Why "none"? Because middle and right have undefined values, resulting in a random value in output.
Note: "Random" might be always the same value, depending on the bits set or reset at the locations of middle and right, respectively.
Quick question: Is it by design that you are falling through your switch-cases?
void Motor_Output(unsigned char x, unsigned char y, unsigned char z){
// ...
switch(output){
case 0x0:
... <-- no break, will continue to execute next case
case 0x1:
... <-- no break, will continue to execute next case
case 0x2:
... <-- no break, will continue to execute next case
case 0x3:
... <-- no break, will continue to execute next case
case 0x4:
... <-- no break, will continue to execute next case
case 0x5:
... <-- no break, will continue to execute next case
case 0x6:
... <-- no break, will continue to execute next case
case 0x7:
... <-- no break, will continue to execute next case
}
return;
}
Related
I'm trying to make a function to make a delay in ATmega32 using Timer0 but I can't get the delay right and when I used debugging I found that the variable T_tick is not changing value from 0 but other operations depend on its value so nothing is working right. I don't know what's wrong with this variable and I've been stuck here for while so please help.
My code is as follows in a single page:
#include <math.h>
#include "registers.h"
#define CPU_frequency 1000000
#define set_bit(x,Bit_num) x|=(1<<Bit_num)
#define clr_bit(x,Bit_num) x&=~(1<<Bit_num)
#define tolge(x,Bit_num) x^=(1<<Bit_num)
//timer configuration
#define Normal 'N'
#define PWM_paseCorrect 'O'
#define PWM_fast 'p'
#define CTC 'Q'
double T_tick = 0,T_maxDelay = 0;
uint32_t overflowsNumber = 0, T_initValue = 0, overflowCounter = 0;
// set the timer mood
void timer0_init(uint8_t timerMood)
{
switch(timerMood)
{
case Normal:
TCCR0 = 0x00;
break;
case PWM_paseCorrect:
TCCR0 = 0x40;
break;
case CTC:
TCCR0 = 0x08;
break;
case PWM_fast:
TCCR0 = 0x48;
break;
}
}
void delayT0(double delay)
{
//convert delay to Ms
delay= delay/1000;
//calculate tick time
T_tick = 1/CPU_frequency;
//calculate max delay time
T_maxDelay = 256*T_tick;
//calculate overflow flag count
overflowsNumber = ceil(delay/T_maxDelay);
//calculate the timer initial value
T_initValue = 256 - (delay/T_tick)/overflowsNumber;
//set timer initial value
TCNT0 = T_initValue;
//start timer in no prescaling mood
set_bit(TCCR0,0);
//Make a loop to count the overflows
overflowCounter = 0;
while (overflowCounter < overflowsNumber)
{
//wait until overflow flag =1
while ((TIFR &(1<<0)) == 0)
//clear overflow flag
set_bit(TIFR,0);
overflowCounter++;
}
overflowCounter = 0;
TCCR0 = 0x00;
}
void LED_init(uint8_t pinNumber)
{
set_bit(DDRA,pinNumber);
}
void LED_TOGLE(uint8_t pinNumber)
{
tolge(PORTA,pinNumber);
}
int main(void)
{
LED_init(0);
timer0_init(Normal);
while (1)
{
LED_TOGLE(0);
delayT0(512);
}
}
The delay is supposed to be 512ms but it's only 1ms because of the variable T_tich that i don't know what's its problem; or that's what i think.
if any one can help please do; i've been stuck in there for too long
your problem is so simple :
in the line T_tick = 1 / CPU_frequency;. after preprocessing , it's expanded to be equivalent to : T_tick = 1 / 1000000; which will always result in zero.
even my compiler gives me this warning in this line :
Clang-Tidy: Result of integer division used in a floating point context; possible loss of precision
as the right hand side is integer division as 1 / 1000000 = 0
so T_tick = 0; , that's why T_tick will be always zero.
so either write T_tick = 1.0 / CPU_frequency; or T_tick = (double)1 / CPU_frequency;.
also don't forget to turn on all your compiler warnings using compiler flags as it will really help.
#include <FirebaseESP8266.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#define FIREBASE_HOST "####"
#define FIREBASE_AUTH "####"
// defines pins numbers
const int trigPin = 2; //D4
const int echoPin = 0; //D3
const int led = 4; //D2
// defines variables
long duration;
int distance = 0;
int wifi = 0;
int water = 0;
int water1 = 0;
//Firebase object..
FirebaseData firebaseData;
WiFiManager wifiManager;
void setup(){
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(led, OUTPUT);
Serial.begin(115200);
wifiManager.autoConnect("Aqua","123456789");
Serial.println();
Serial.print("Connected, IP address:" );
Serial.print(WiFi.localIP());
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}
void loop(){
//digitalWrite(led, LOW);
if(WiFi.status() != WL_CONNECTED){
wifi = 0;
if (Firebase.setInt(firebaseData, "/Connectivity", wifi)){}
wifiManager.autoConnect("Aqua","123456789");
}
else{
wifi = 1;
if (Firebase.setInt(firebaseData, "/Connectivity", wifi)){}
}
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
if (Firebase.setInt(firebaseData, "/Distance", distance)) {
Serial.print("Distance = ");
Serial.println(distance);
Serial.println("\n");
delay(1000);
}
else
Serial.println(firebaseData.errorReason());
distance= duration*0.034/2;
water1 = water;
switch(distance){
case 2:
case 3:water = 500;
break;
case 4:
case 5:
case 6: water = 400;
break;
case 7:
case 8:water = 300;
break;
case 9:
case 10:
case 11:water = 200;
break;
case 12:
case 13:
case 14: water = 100;
break;
case 15: water = 0;
break;
default : water = water1;
break;
}
//I WANT TO STORE DISTANCE'S VALUE AND CHECK IF ITS THE SAME LAST 5 TIMES THEN EXECUTE BELOW CODE
if (Firebase.setInt(firebaseData, "/WaterLevel", water)) {
}
else
Serial.println(firebaseData.errorReason());
}
I WANT TO STORE DISTANCE'S VALUE AND CHECK IF ITS THE SAME LAST 5 TIMES
The distance's value is generated again and again I just want to store the previous 5 value of distance and compare them, and if they are same then execute the last if() condition
Is there a way to store only the previous 5 values generated by the variable "distance" and check if they are same
First, declare a local integer variable at the top:
int distanceSame = 1;
Then another one storing the last value:
int lastDistance = -1;
After this line
distance= duration*0.034/2;
check if the current distance value matches lastDistance variable, and if so, increment the distanceSame, otherwise reset it like this:
if(distance == lastDistance) {
// Increment counter
distanceSame++;
} else {
distanceSame = 1;
}
// prepare lastDistance for next cycle
lastDistance = distance;
And execute your code if the previous 5 values of distance are same.
if(distanceSame >= 5) {
if (Firebase.setInt(firebaseData, "/WaterLevel", water)) {
}
else
Serial.println(firebaseData.errorReason());
}
}
I'm working on calculator project using LM3S316 microcontroller & Keil software
I have some confusion about how can I work with KEYPAD-SMALLCALC
So, my question is :
how can I use this keypad and initialize it
also, how can I represent values and use it
finally, how to connect it with LCD
Thank You
The KEYPAD-SMALL-CALC is a matrix keypad, meaning you should configure some pins as input and some pins as output.
This is a decent library that i personally have used for a project of mine using a matrix keypad - https://github.com/nimaltd/KeyPad
You should be able to integrate it in your code without too much issues.
In short you have cols and rows. In the example provided the rows are input pins and the cols are output pins. There is a for cycle that is checking for a button press. By default rows are high, once a button is pressed the library checks for a combination between row and col that determinate which button has been pressed.
For configuration pins the easiest way would probably to use software such as "STM32CubeMX" which generates c code with your MCU configuration, you can easily configurate there the matrix keypad rows, cols and decide which pins you should use for the LCD.
Edit : Here is a modified version of the github library i have personally used in a project
source keyboard.c
#include "keyboard.h"
//#define _KEYPAD_DELAY(x) HAL_Delay(x)
const GPIO_TypeDef* _KEYPAD_COLUMN_GPIO_PORT[] =
{
COL_1_GPIO_Port,
COL_2_GPIO_Port,
COL_3_GPIO_Port,
COL_4_GPIO_Port,
COL_5_GPIO_Port,
COL_6_GPIO_Port,
COL_7_GPIO_Port,
COL_8_GPIO_Port
};
const uint16_t _KEYPAD_COLUMN_GPIO_PIN[] =
{
COL_1_Pin,
COL_2_Pin,
COL_3_Pin,
COL_4_Pin,
COL_5_Pin,
COL_6_Pin,
COL_7_Pin,
COL_8_Pin
};
const GPIO_TypeDef* _KEYPAD_ROW_GPIO_PORT[] =
{
ROW_1_GPIO_Port,
ROW_2_GPIO_Port,
ROW_3_GPIO_Port,
ROW_4_GPIO_Port
};
const uint16_t _KEYPAD_ROW_GPIO_PIN[] =
{
ROW_1_Pin,
ROW_2_Pin,
ROW_3_Pin,
ROW_4_Pin
};
KeyPad_t KeyPad;
//#############################################################################################
void KeyPad_Init(void)
{
KeyPad.ColumnSize = sizeof(_KEYPAD_COLUMN_GPIO_PIN)/2;
KeyPad.RowSize = sizeof(_KEYPAD_ROW_GPIO_PIN)/2;
}
//#############################################################################################
uint16_t KeyPad_Scan(void)
{
uint16_t key = 0;
uint8_t hold_key = 0;
int int_btn_cnt = 0;
int int_button_state_change = 0;
GPIO_PinState int_button_current_state = GPIO_PIN_SET;
GPIO_PinState int_button_last_state = GPIO_PIN_SET;
for(uint8_t c=0 ; c<KeyPad.ColumnSize ; c++)
{
for(uint8_t i=0 ; i<KeyPad.ColumnSize ; i++)
HAL_GPIO_WritePin((GPIO_TypeDef*)_KEYPAD_COLUMN_GPIO_PORT[i],_KEYPAD_COLUMN_GPIO_PIN[i],GPIO_PIN_SET);
HAL_GPIO_WritePin((GPIO_TypeDef*)_KEYPAD_COLUMN_GPIO_PORT[c],_KEYPAD_COLUMN_GPIO_PIN[c],GPIO_PIN_RESET);
for(uint8_t r=0 ; r<KeyPad.RowSize ; r++){
while(HAL_GPIO_ReadPin((GPIO_TypeDef*)_KEYPAD_ROW_GPIO_PORT[r],_KEYPAD_ROW_GPIO_PIN[r])==GPIO_PIN_RESET){
int_btn_cnt++;
if(int_btn_cnt == _KEYPAD_DEBOUNCE_TIME_MS){
key |= 1<<c;
key |= 1<<(r+8);
return key;
}
}
int_btn_cnt = 0;
}
}
return key;
}
//#############################################################################################
uint16_t KeyPad_WaitForKey(uint32_t Timeout_ms)
{
volatile uint16_t keyRead;
while(Timeout_ms==0)
{
keyRead = KeyPad_Scan();
if(keyRead!=0)
{
KeyPad.LastKey = keyRead;
return keyRead;
}
}
uint32_t StartTime = HAL_GetTick();
while(HAL_GetTick()-StartTime < Timeout_ms)
{
keyRead = KeyPad_Scan();
if(keyRead!=0){
KeyPad.LastKey = keyRead;
return keyRead;
}
}
return 0;
}
//#############################################################################################
char KeyPad_WaitForKeyGetChar(uint32_t Timeout_ms)
{
char result = 0;
switch(KeyPad_WaitForKey(Timeout_ms))
{
case 0x802: // ^
result = '^';
break;
case 0x804: // 7
result = '7';
break;
case 0x808: // 7
result = '8';
break;
case 0x810: // 9
result = '9';
break;
case 0x820: // 04
result = 0xFF;
break;
case 0x840: // D+
result = 0xFE;
break;
case 0x880: // M
result = 'M';
break;
case 0x401: // -%
result = '-';
break;
case 0x402: // +%
result = '+';
break;
case 0x404: // 4
result = '4';
break;
case 0x408: // 6
result = '5';
break;
case 0x410: // 6
result = '6';
break;
case 0x420: // 03
result = 0xFD;
break;
case 0x440: // PRUREP
result = 0xFC;
break;
case 0x480: // STL
result = 0xFB;
break;
case 0x201: // ALT
result = 0xFA;
break;
case 0x202: // CLK
result = 0xF9;
break;
case 0x204: // 1
result = '1';
break;
case 0x208: // 3
result = '2';
break;
case 0x210: // 3
result = '3';
break;
case 0x220: // 02
result = 0xF8;
break;
case 0x240: // PY1 RA
result = 0xF7;
break;
case 0x101: // C
result = 'C';
break;
case 0x102: // VD
result = 0xF6;
break;
case 0x104: // 0
result = '0';
break;
case 0x108: // .
result = '.';
break;
case 0x110: // QTY
result = 0xF5;
break;
case 0x120: // 01
result = 0xF4;
break;
case 0x140: // PY2PO
result = 0xF3;
break;
case 0x180: // TL
result = 0xF2;
break;
}
return result;
}
and the header file keyboard.h
#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
#include <stdint.h>
#include <stdbool.h>
typedef struct
{
uint8_t ColumnSize;
uint8_t RowSize;
uint16_t LastKey;
}KeyPad_t;
void KeyPad_Init(void);
uint16_t KeyPad_WaitForKey(uint32_t Timeout_ms);
char KeyPad_WaitForKeyGetChar(uint32_t Timeout_ms);
#define _KEYPAD_DEBOUNCE_TIME_MS 5
#endif /* __KEYBOARD_H__ */
You should only configure the const arrays with the ports and pins you are planning to use and use the library like this :
init keyboard at the start of your program:
KeyPad_Init();
and use it like this
uint8_t key = KeyPad_WaitForKeyGetChar(1); // wait 1 ms
key is the value of the pressed key, if you use KeyPad_WaitForKeyGetChar(0) the code will stay here and wait for a key press.
Hope it helps!
I'm trying to turn on the relay for 5s when I press the button(U), then turn it off. Then switch on the second one for 10 seconds and turn it off.I would like to use the millis function to control 8 relays at different time intervals.
Please correct my code.
Why doesn't it work?
(code with one relay)
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int ssr1 = 2;
int ssr2 = 3;
int lcd_key = 0;
int adc_key_in = 0;
#define R 0
#define U 1
#define D 2
#define L 3
#define S 4
#define N 5
unsigned long interval = 5000;
unsigned long previousMillis = 0;
int read_LCD_buttons(){
adc_key_in = analogRead(0);
if (adc_key_in > 1000) return N;
if (adc_key_in < 50) return R;
if (adc_key_in < 250) return U;
if (adc_key_in < 450) return D;
if (adc_key_in < 650) return L;
if (adc_key_in < 850) return S;
return N;
}
void setup(){
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("Select:");
pinMode(3, OUTPUT);
}
void loop(){
unsigned long currentMillis = millis();
lcd.setCursor(0,1);
lcd_key = read_LCD_buttons();
switch (lcd_key){
case U:{
digitalWrite(3, HIGH);
if ((unsigned long)(currentMillis - previousMillis) >= interval){
digitalWrite(3, LOW);
previousMillis = millis();
}
lcd.print("START");
break;
}
case D:{
digitalWrite(3, LOW);
lcd.print("STOP");
break;
}
case N:{
break;
}
}
}
I suggest you check out various Arduino tutorials.
However, based on your request, I have included example code below.
Please note that this has not been tested. However, you should get an idea of the logic and adapt accordingly.
There are many other ways to achieve the same result.
int relayState = RELAY_STATE_OFF; // track state of the relay
unsigned long relayOnAt = 0; // time at which relay was turned ON
void relay(int turnOn)
{
if( turnOn == ON ) digitalWrite(3,HIGH);
else digitalWrite(3,LOW);
}
void processRelay(int operateRelay)
{
switch(relayState){
case RELAY_STATE_OFF:
if( operateRelay == 1) {
relay(ON);
relayState = RELAY_STATE_ON;
relayOnAt = millis(); // remember when the relay was turned on
}
break;
case RELAY_STATE_ON: // wait here for interval seconds to elapse
if( millis() - relayOnAt >= interval) {
relay(OFF);
relayState = RELAY_STATE_OFF; // go back to checking key input
}
break;
default:
relayState = RELAY_STATE_OFF;
break;
}
}
int operateRelay = 0;
void loop(){
lcd.setCursor(0,1);
lcd_key = read_LCD_buttons();
operateRelay = 0;
if( lcd_key == U ) {
operateRelay = 1;
}
processRelay(operateRelay);
}
I am trying to interface an Atmega32 micro-controller with a 16x2 LCD and a 4x4 keypad matrix. I am simulating with Proteus and using WinAVR compiler.
The LCD part is okay (I have thoroughly tested it). The keypad code, however, is not running as I expect. Whenever I press a key, the scanning of keypad rows stops indefinitely.
Also the key doesn't display on the LCD. Please help me find the bug.
Below is the circuit schematic as drawn in Proteus, as well as the code. I have not included code for the LCD here since I know that part is working perfectly well.
Circuit:
Code:
#include <avr/io.h>
#include<util/delay.h>
//Keypad Information
#define R0 0
#define R1 1
#define R2 2
#define R3 3
#define C0 4
#define C1 5
#define C2 6
#define C3 7
#define keypadPORT PORTA
#define keypadPIN PINA
#define keypadDDR DDRA
//Keypad functions and global variables
char getkey();
int keypadRow[] = {R0, R1, R2, R3}; //rows of the keypad
int keypadCol[] = {C0, C1, C2, C3};//columnd
int main()
{
char key_pressed;
keypadDDR |= (1<<R0)|(1<<R1)|(1<<R2)|(1<<R3);//set upper part of keypad port as output
//this will be required for scanning the rows
keypadDDR &= ~((1<<C0)|(1<<C1)|(1<<C2)|(1<<C3));//set lower part of keypad port as input.This is
//the part of the keypad port where the rows are connected.
LCD_init(); //initialize LCD
while(1)
{
key_pressed = getkey();
switch(key_pressed)
{
case('A'):
break;//do nothing if no key is pressed
default:
send_char(key_pressed);//send the key pressed to LCD
}
}
return 0;
}
char getkey()
{
int i, j;
for(i = 0; i < 4; i++)
{
keypadPORT = 0x00;
keypadPORT |= (1 << keypadRow[i]);//send a high to a particular row of the keypad
for(j = 0; j < 4; j++)
{
if(bit_is_set(keypadPIN,keypadCol[j]))//check if key is pressed
{
while(bit_is_set(keypadPIN,keypadCol[j])); //wait for key to be released
switch(i)
{
case(0):
{
if (j == 0) return '7';
else if (j == 1) return '8';
else if (j == 2) return '9';
else if (j == 3) return '/';
break;
}
case(1):
{
if (j == 0) return '4';
else if (j == 1) return '5';
else if (j == 2) return '6';
else if (j == 3) return '*';
break;
}
case(2):
{
if (j == 0) return '1';
else if (j == 1) return '2';
else if (j == 2) return '3';
else if (j == 3) return '-';
break;
}
case(3):
{
if (j == 0) return '?';
else if (j == 1) return '0';
else if (j == 2) return '=';
else if (j == 3) return '+';
break;
}
}
}
}
}
return 'A';//Return 'A' if no key is pressed.
}
If, whenever you press a key, "the scanning of keypad rows stops indefinitely" and "the key doesn't display on the LCD", then I'd be looking at any potential infinite loops, such as the following line:
while(bit_is_set(keypadPIN,keypadCol[j]));
I don't know whether the columns drain away to ground or stay high when you release the key but you should be able to check that behaviour by replacing that line with:
send_char('<');
while(bit_is_set(keypadPIN,keypadCol[j]));
send_char('>');
If you are indeed getting caught in an infinite loop there, the display should show you the <.