Electronic – PIC programming – Get value of multiple buttons to a port

buttoncmicrocontrollerpic

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 8×8 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.

Best Answer

There are a number of things that need fixing in your code before we can start to assist with the functional problems. I have listed a few below.

Use of TRIS

Please see the answer from Handoko, which deals with this.

Use of LAT vs. PORT registers

You call your function like this: Send1byte(getMatrixX(LATA)). I assume your intention is to get the current status of the input buttons and send them to this function.

This will not work, you need to read from the PORTA register instead. The correct code would read Send1byte(getMatrixX(PORTA)).

Why is this? There is a short explanation in the datasheet:

Reading the PORTA register reads the status of the pins; writing to it will write to the port latch.

And a helpful image:

Figure 10-1 PORT vs. LAT

The internal data line which is used when you read the PORT bit (bottom left, from the green block) is connected to the input buffer, which comes directly from the I/O pin. In contrast the data line used when you read the LAT bit (top left, connected to the red block) only reads the status of the data latch. It is not connected to the input.

Note that the SCK/DATA/SCL definitions should work (writing to the PORT bit will set the LATch) but I usually keep all writes to the LATch except where impossible (e.g. bidirectional busses).

Configuration of analogue functions

You need to disable the analogue functions which are multiplexed onto PORTA pins. See this note from the datasheet:

On a Power-on Reset, RA5 and RA3:RA0 are configured as analog inputs and read as ‘0’. (section 10, page 113)

In addition the comparator function also needs to be disabled. To set all PORTA pins to digital inputs, see Register 21-2 (ADCON1) in the datasheet. You might try:

ADCON1 = 0x0F; // All digital inputs
CMCON = 0x07;  // Comparators off (note this is the POR default)

If you don't do this then you will never get the input data from your switches, unless the Proteus simulator does unusual things.

Simplifying getMatrixX()

You could simplify your getMatrixX() function in a number of ways, depending if you care about code or data space. Here's one which uses a table lookup (untested):

unsigned char data[8] = { 0b01111111, 0b10111111, 0b11011111, 0b11101111, 0b11110111, 0b11111011, 0b11111101, 0b01111110 };

unsigned char getMatrixX(unsigned char in_X) {
  if (in_X > 7) {
    return 0xFF;
  }

  return data[in_X];
}

It would be simple to do the same thing with a shift and some logic, avoiding the lookup table:

unsigned char getMatrixX(unsigned char in_X) {
  if (in_X > 7) {
    return 0xFF;
  }

  return 0xFF ^ (0x80 >> in_X);
}
Related Topic