PIC programming - Get value of multiple buttons to a port - c++

I'm learning PIC (pic18f4550) and pretty new to microcontroller programming. I'm trying get value of three button on PORTA and send it to a 8x8 led matrix as X coordinates through a 74LS595. The problem is that the value go to the led matrix doesnt change when i pressed the buttons to create different value. I'm simulating on Proteus so I guess I don't need debounce function.
Here's my code and schematic:
#include<p18f4550.h>
#define SCK LATBbits.LATB0
#define DATA PORTBbits.RB1
#define SCL PORTBbits.RB2
void Data_in(unsigned char k){
DATA=k;
SCK=0;
SCK=1;
}
void LatchData(){
SCL=0;
SCL=1;
}
void Send1byte(unsigned char data)
{
unsigned char i,temp;
for(i=0;i<8;i++)
{
temp = data & (1<<i);
if(temp)
{
DATA = 1;
}
else
{
DATA = 0;
}
SCK = 0;
SCK = 1;
}
SCL = 0;
SCL = 1;
}
unsigned char getMatrixX(unsigned char in_X)
{
switch(in_X)
{
case 0: // the value stuck here
return 0b01111111;
case 1:
return 0b10111111;
case 2:
return 0b11011111;
case 3:
return 0b11101111;
case 4:
return 0b11110111;
case 5:
return 0b11111011;
case 6:
return 0b11111101;
case 7:
return 0b11111110;
default:
return 0b11111111;
}
}
void main()
{
TRISA = 1;
TRISC = 1;
TRISB = 0;
TRISD = 0;
PORTD = 0x80;
while(1){
Send1byte(getMatrixX(LATA));
}
}
This is link to my schematic:
my schematic
Really appreciate any solutions and advices. Sorry for my bad english.

the analogue function of RA0:RA3 is the real problem here, so adding these will fix:
ADCON1 = 0x0F; // All digital inputs
CMCON = 0x07; // Comparators off (note this is the POR default)
Thanks David in this question: https://electronics.stackexchange.com/questions/111614/pic-programming-get-value-of-multiple-buttons-to-a-port/111625?noredirect=1#111625 , he explained it very well.

Related

Interrupt is sometimes adding two (repeated) elements to array instead of one

Im trying to write code that records LED's when a button is pressed, stores them into an array, and when that array is 5 long, it stops cycling through LED colours and plays the recorded pattern. It sometimes works perfectly, however sometimes it will double record a single button press/led colour. I can't figure out why. If anyone could let me know any possible issues it would be much appreciated :).
Here's the code (C++):
#include "mbed.h"
#include <vector>
// Green LED
DigitalOut led1(LED1);
// Blue LED
DigitalOut led2(LED2);
// Red LED
DigitalOut led3(LED3);
// Button Interrupt
InterruptIn button(USER_BUTTON);
// Initialise counter for button presses (n), and selector for the lit LED (l)
int n = 0;
int l = 1;
// Define sequence length
int sequence_length=5;
// Create vector/list for recorded LED's to go into
int sequence[5];
// Callback function to associate with the press button event
void onButtonPress()
{
led1 = true;
led2 = true;
led3 = true;
// Add corresponding led to 'sequence'
sequence[n] = l;
n = n + 1;
}
// 'Decoding' what LED's should be lit up for different 't' values in main
void select_led(int l)
{
if (l==0) {
led1 = false;
led2 = false;
led3 = false;
}
else if (l==1) {
led1 = true;
led2 = false;
led3 = false;
}
else if (l==2) {
led1 = false;
led2 = true;
led3 = false;
}
else if (l==3) {
led1 = false;
led2 = false;
led3 = true;
}
}
int main() {
// attach the address of the callback function to the rising edge
button.rise(onButtonPress);
while (true) {
while (n >= sequence_length) {
select_led(0);
wait(1);
for (int i = 0; i < n; i++) {
select_led(sequence[i]);
wait(0.5);
select_led(0);
wait(0.5);
}
}
select_led(l);
wait(1);
l = l + 1;
if (l==4) {
l = 1;
}
}
}
I'm not sure if its a logic issue or if its dependent on the length of the button press, or another unconsidered factor.
Your problem probably has to do with the way you press the button. If there is even a little hesitation the button will recognize two presses and not one. Try adding a wait to the end of the onButtonPress function in order to account for this occurrence.

Fade leds with serial communication Arduino

I am getting serial communication and trying to make an led fade effect ,
This is my function for leds which is facing latency issues , obviously the for loop . Can anyone suggest a better logic or solution to approach this without getting latency in leds?
void loop() {
// serial communication
while(Serial.available() > 0 ){
int inByte = Serial.read();
Serial.print(inByte);
if (inByte > 0) {
// if byte is 255, then the next 3 bytes will be new rgb value
if (inByte == 255) {
setColors = true;
colorSetCounter = 0;
} else if (setColors) {
switch (colorSetCounter) {
case 0:
redVal = inByte;
break;
case 1:
greenVal = inByte;
break;
case 2:
blueVal = inByte;
setColors = false;
receiveNotes = true;
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
break;
}
colorSetCounter++;
} else if (receiveNotes) {
controlLeds(inByte);
}
}
}
}
void controlLeds (int note) {
note -= 1;
if (!leds[note]) {
leds[note].red = redVal;
leds[note].green = greenVal;
leds[note].blue = blueVal;
}
else {
for(int i =0; i<=255; i++){
leds[note].fadeToBlackBy(i);
FastLED.show();
if(!leds[note]){
break;
}
}
}
FastLED.show();
}
You need to write non-blocking code as Scheff mentioned. Instead of a global variable, you can use a static variable in a function. It remembers its value for each call of that function.
Here is an example how you could do it, using millis(). My code fades an LED on and off if some serialEvent happens and it does not block the rest of the code:
const int ledPin = 13;
int setValue = 0;
unsigned long lastTime = 0;
const unsigned long refreshTime = 200;
char buffer1[8];
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
if (millis() - lastTime > refreshTime)
{
lastTime = millis();
fadeLED(setValue);
}
}
void fadeLED(int fadeValue)
{
static int currentValue = 0;
if (fadeValue > currentValue) {
currentValue++;
}
if (fadeValue < currentValue) {
currentValue--;
}
analogWrite(ledPin, currentValue);
}
void serialEvent()
{ Serial.readBytesUntil('\n', buffer1, 8);
switch (setValue)
{
case 0:
setValue = 255;
break;
case 255:
setValue = 0;
break;
default:
break;
}
}

Clear before writing new string using glutbitmapcharacter

I am using the following function in my code. It prints the desired message on screen for any mode.The problem is when I call my function for 2nd time to print something new on window, it overwrites on previous message.How do I clear the previous thing I wrote before writing the new one?
void output(float r, float g, float b,int mode )
{
glColor3f( r, g, b );
glRasterPos2f(25, 25);
int len, i;
char string1[50] = "Edit Mode Enabled";
char string2[50] = "Edit Mode Disabled";
char string3[50] = "Delete Mode Enabled";
char string4[50] = "Delete Mode Disabled";
char string[50];
switch(mode)
{
case 1: strcpy(string,string1); break;
case 2: strcpy(string,string2); break;
case 3: strcpy(string,string3); break;
case 4: strcpy(string,string4); break;
}
cout << string <<endl;
len = (int)strlen(string);
for (i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, string[i]);
}
}

Calculator Based on ATMega8 using AVRstudi

About the Calculator:
Basically this calculator is made to calculate the resistance of copper and aluminum wires at the ambient temperature using the formula
R2= R1*(1+alpha(T-25))
Here R2 will be the output, R1 will be the value entered by the user using a 4x4 matrix keypad (which will include decimal values like 12.5 etc), T is the temperature in degree Celsius recorded by the temperature sensor LM35.
alpha for copper = 0.0039
alpha for aluminum = 0.0042
How it should work:
Basically the temperature will be recorded by the calculator which will give the input T. The value of resistance at 25deg C will be fed by the user using keypad.
Now the keys 0-9 and "." are used to enter the value.
After this when the user presses say "+" on keypad, it should implement the formula for copper and show the result on LCD, similarly when the user presses "-" it should implement the formula for aluminum. Let us leave the "*" "/" and "=" buttons as spare for the time being.
Progress till now:
Using the codes which I have sent you in this attachment, I am able to get the temperature on screen correctly, I am able to see the value of R1 (i.e value of resistance at 25deg C) Now I cannot figure out how to use these values to get the output.
Please help me with this. :)
Thanks & Regards,
Mohit Goyal
#define F_CPU 1000000UL
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include "lcd.h"
#include "lcd.c"
#include <math.h>
#define KB_PORT_OUT PORTB
#define KB_PORT_IN PINB
void port_init(void)
{
DDRB = 0x0f; //Key-board port, higer nibble - input, lower nibble - output
PORTB = 0xff;
}
void init_devices(void)
{
port_init();
MCUCR = 0x00;
TIMSK = 0x00; //timer interrupt sources
}
void InitADC()
{
ADMUX=(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS1)|(1<<ADPS0);
}
uint16_t ReadADC (uint8_t ch)
{
ch=ch&0b00000111;
ADMUX|=ch;
ADCSRA|=(1<<ADSC);
while (! (ADCSRA & (1<<ADIF)));
ADCSRA|=(1<<ADIF);
return (ADC);
}
void Wait ()
{
uint8_t i;
for (i=0;i<1;i++)
_delay_loop_2(0);
}
void main()
{
char Temp[3];
uint16_t adc_result,mV;
int t;
lcd_init (LCD_DISP_ON);
lcd_clrscr();
InitADC();
lcd_gotoxy(0,0);
lcd_puts("R1=");
lcd_gotoxy(9,0);
lcd_puts(",T=");
lcd_gotoxy(15,0);
lcd_puts("C");
lcd_gotoxy(0,1);
lcd_puts("R2=");
while(1)
{
adc_result=ReadADC(0);
mV=(int)(1000.0*5.0*(((float)adc_result)/1023.0));
t=(int)(mV/10);
sprintf(Temp,"%d",t);
lcd_gotoxy(12,0);
lcd_puts(Temp);
Wait();
unsigned char Res, upperNibble, myCharPointer, keyCode, keyPressed, j;
int a=0, b=0, c=0, d=0, display=0;
init_devices();
lcd_gotoxy(3,0);
while(1)
{
upperNibble = 0xff;
for(j=0; j<4; j++)
{
_delay_ms(1);
KB_PORT_OUT = ~(0x01 << j);
_delay_ms(1); //delay for port o/p settling
upperNibble = KB_PORT_IN | 0x0f;
if (upperNibble != 0xff)
{
_delay_ms(20); //key debouncing delay
upperNibble = KB_PORT_IN | 0x0f;
if(upperNibble == 0xff) goto OUT;
keyCode = (upperNibble & 0xf0) | (0x0f & ~(0x01 << j));
while (upperNibble != 0xff)
upperNibble = KB_PORT_IN | 0x0f;
_delay_ms(20); //key debouncing delay
switch (keyCode) //generating key characetr to display on LCD
{
case (0xee): keyPressed = "1";
a=1;
b=b*10+1;
break;
case (0xed): keyPressed = "4";
a=4;
b=b*10+4;
break;
case (0xeb): keyPressed = "7";
a=7;
b=b*10+7;
break;
case (0xe7): keyPressed = ".";
break;
case (0xde): keyPressed = "2";
a=2;
b=b*10+2;
break;
case (0xdd): keyPressed = "5";
a=5;
b=b*10+5;
break;
case (0xdb): keyPressed = "8";
a=8;
b=b*10+8;
break;
case (0xd7): keyPressed = "0";
a=0;
b=b*10+0;
break;
case (0xbe): keyPressed = "3";
a=3;
b=b*10+3;
break;
case (0xbd): keyPressed = "6";
a=6;
b=b*10+6;
break;
case (0xbb): keyPressed = "9";
a=9;
b=b*10+9;
break;
case (0xb7): keyPressed = "=";
break;
case (0x7e): keyPressed = "A";
break;
case (0x7d): keyPressed = "B";
break;
case (0x7b): keyPressed = "C";
break;
case (0x77): keyPressed = "D";
break;
default : keyPressed = "X";
}//end of switch
lcd_puts(keyPressed);
lcd_gotoxy(3,1);
lcd_puts(keyPressed);
OUT:;
}//end of if
}//end of for
}//end of while(1)
return 0;
}
}
One way to read input is read characters in character array(in your switch case block append keypressed to character array using strcat function). Then check whether it is in right format. And then convert the number in character array to float and use it in calculation as explained in question link
The way to append keypressed to string:
char s[25]="";
strcat(s,"1")
There is one error I noticed Change
keypressed="1"
to
keypressed='1'
in all such cases. "1" is const character array. '1' is character
or change the type of keypressed character array and use strcpy to assign any string to it.
strcpy(keypressed,"1")

string manipulating in C?

I want to print an array of characters, these characters are underscores first.
Then the user can write characters on these underscores.I used gotoxy() but it doesn't work properly.
That is what i wrote:
int main(void)
{
char arr[20];
int i;
char ch;
clrscr();
for(i=0;i<=20;i++)
{
textattr(0x07);
cprintf("_");
}
do
{
for(i=0;i<=20;i++)
{
//gotoxy(i,0);
//ch = getche();
if( isprint(ch) == 1)
{
arr[i] = ch;
gotoxy(i,0);
//printf("%c",ch);
}
}
} while(i == 20);
getch();
return 0;
}
The first thing is this: You probably don't want to have all those calls to gotoxy, textattr and cprintf in your main function, since that is not what the main function is supposed to do.
It is much more likely that the main function's purpose is "to read some text from the user, presented nicely in an input field". So you should make this a function:
static int
nice_input_field(char *buf, size_t bufsize, int x, int y) {
int i, ch;
gotoxy(x, y);
for (i = 0; i < bufsize - 1; i++) {
cprintf("_");
}
i = 0;
gotoxy(x, y);
while ((ch = readkey()) != EOF) {
switch (ch) {
case '...': /* ... */
break;
case '\b': /* backspace */
cprintf("_");
i--;
gotoxy(x + i, y);
break;
case '\t': /* tabulator */
case '\n': /* enter, return */
buf[i] = '\0';
return 0; /* ok */
default: /* some hopefully printable character */
if (i == bufsize - 1) {
cprintf("\a"); /* beep */
} else {
buf[i++] = ch;
gotoxy(x + i, y);
cprintf("%c", buf[i]);
}
}
}
/* TODO: null-terminate the buffer */
return 0;
}
Printing an array of characters is fairly easy:
char* str = your_array;
while(*str) {
putc(*str++);
}
From memory that should print a string out to the screen.
Your code is very DOS-specific. There is not a good general solution to the problem of reading immediate input in a portable way. It does get asked quite often, so I think the C FAQ broke down and included an answer which you might want to seek out.
That said, I think your bug is that gotoxy(1, 1) is the upper corner of the screen, not 0,0. So you want gotoxy(i, 1)