Yet another 4x4 keyboard topic

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello!

 

I'm having a problem implementing 4x4 keyboard to ATmega16, problem is that the script always detects a key, no matter if it's pressed or not. Problem also occurs if no keyboard at all is connected 

 

MCUCSR|=(1<<JTD);

char getKey()
{

	DDRC = 0x0F;
	PORTC = 0xF0;

	PORTC = (1<<PC0);
	_delay_ms(100);
	if ( (PINC & ~(1<<PC4)) ) return "D"; //D
	if ( (PINC & ~(1<<PC5)) ) return "C"; //C
	if ( (PINC & ~(1<<PC6)) ) return "B"; //B
	if ( (PINC & ~(1<<PC7)) ) return "A"; //A


	PORTC = (1<<PC1);
	_delay_ms(100);
	if ( (PINC & ~(1<<PC4)) ) return "#"; //#
	if ( (PINC & ~(1<<PC5)) ) return "9"; //9
	if ( (PINC & ~(1<<PC6)) ) return "6"; //6
	if ( (PINC & ~(1<<PC7)) ) return "3"; //3


	PORTC = (1<<PC2);
	_delay_ms(100);
	if ( (PINC & ~(1<<PC4)) ) return "0"; //0
	if ( (PINC & ~(1<<PC5)) ) return "8"; //8
	if ( (PINC & ~(1<<PC6)) ) return "5"; //5
	if ( (PINC & ~(1<<PC7)) ) return "2"; //2


	PORTC = (1<<PC3);
	_delay_ms(100);
	if ( (PINC & ~(1<<PC4)) ) return "*"; //*
	if ( (PINC & ~(1<<PC5)) ) return "7"; //7
	if ( (PINC & ~(1<<PC6)) ) return "4"; //4
	if ( (PINC & ~(1<<PC7)) ) return "1"; //1

	return  "f";

}

 

PS. key shown as being "pressed" is more-less random.

PS2. Tried different if statements (even totally inversed ones, but still the same occurs)

 

Any suggestions why? Maybe some hardware related bug?

This topic has a solution.

Last Edited: Sun. Feb 1, 2015 - 10:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You normally write one column output LOW,  and read the port with all other rows and columns as pulled-up inputs.

 

You appear to be writing one column output HIGH.    And in the process,  disabling any pull-ups on inputs.

 

David.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

• Bit 7 – JTD: JTAG Interface Disable
When this bit is zero, the JTAG interface is enabled if the JTAGEN Fuse is programmed. If this bit is one, the JTAG interface is disabled. In order to avoid unintentional disabling or enabling of the JTAG interface, a timed sequence must be followed when changing this bit: The application software must write this bit to the desired value twice within four cycles to change its value.

 

If the JTAG interface is left unconnected to other JTAG circuitry, the JTD bit should be set to one. The reason for this is to avoid static current at the TDO pin in the JTAG interface.

uint8_t jtd = MCUCSR | (1<<JTD);
MCUSR = jtd;
MCUSR = jtd;

Remember to disable interrupts during the above sequence.

 

Also, you enable pullups which is correct:

	PORTC = 0xF0;

... but then you disable them immediately:

	PORTC = (1<<PC0);

You're also driving 3 of the 4 output lines low, instead of only 1.

 

Instead:

	PORTC = ~(1<<PC0);
.
.
.
	PORTC = ~(1<<PC1);
.
.
.
	PORTC = ~(1<<PC2);
.
.
.
	PORTC = ~(1<<PC3);

You also need to test for a low value on the given input:

	if ( !(PINC & (1<<PC4)) ) return "D"; //D
	if ( !(PINC & (1<<PC5)) ) return "C"; //C
	if ( !(PINC & (1<<PC6)) ) return "B"; //B
	if ( !(PINC & (1<<PC7)) ) return "A"; //A

Untested.

 

Why such a long delay between writing to PORTC and reading PINC?

 

EDIT: and as David mentions, you generally only ever drive low as an output, not high.  Otherwise multiple key-presses could end up shorting a low output pin with a high output pin.  So:

char getKey()
{

    DDRC = (1<<PC0);
    PORTC = ~(1<<PC0);
    _delay_ms(100);
    if ( !(PINC & (1<<PC4)) ) return "D"; //D
    if ( !(PINC & (1<<PC5)) ) return "C"; //C
    if ( !(PINC & (1<<PC6)) ) return "B"; //B
    if ( !(PINC & (1<<PC7)) ) return "A"; //A


    DDRC = (1<<PC1);
    PORTC = ~(1<<PC1);
    _delay_ms(100);
    if ( !(PINC & (1<<PC4)) ) return "#"; //#
    if ( !(PINC & (1<<PC5)) ) return "9"; //9
    if ( !(PINC & (1<<PC6)) ) return "6"; //6
    if ( !(PINC & (1<<PC7)) ) return "3"; //3


    DDRC = (1<<PC2);
    PORTC = ~(1<<PC2);
    _delay_ms(100);
    if ( !(PINC & (1<<PC4)) ) return "0"; //0
    if ( !(PINC & (1<<PC5)) ) return "8"; //8
    if ( !(PINC & (1<<PC6)) ) return "5"; //5
    if ( !(PINC & (1<<PC7)) ) return "2"; //2


    DDRC = (1<<PC3);
    PORTC = ~(1<<PC3);
    _delay_ms(100);
    if ( !(PINC & (1<<PC4)) ) return "*"; //*
    if ( !(PINC & (1<<PC5)) ) return "7"; //7
    if ( !(PINC & (1<<PC6)) ) return "4"; //4
    if ( !(PINC & (1<<PC7)) ) return "1"; //1

    return  "f";

}

Also untested.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Sun. Feb 1, 2015 - 11:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh sorry, for that, I am a bit tired. First thing I tried was solutions that you guys gave, but since it gave exactly the same results, I figured that why not test totally illogical scenarios, but that's not the point.

I've tested your code joey and now I always get "D", even with keyboard physically disconnected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you properly disable JTAG as I mentioned at the top of my post?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joey, thanks it helped,

the funny thing is that earlier (whole the time) I had at the very begining of the code:

MCUCSR|=(1<<JTD);
MCUCSR|=(1<<JTD);

and it didn't work, and now when I did it like you said:

 

uint8_t jtd = MCUCSR | (1<<JTD);
MCUSR = jtd;
MCUSR = jtd;

it did. 

 

Thanks again

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's hard to say without looking at your compiled code, but the best guess is that there was more than 4 cycles between the two writes to MCUCSR.  In post #3 I quoted from the datasheet the bit about the required timed sequence.  The code I provided stands a better chance of meeting that requirement.  If you want a definitive answer, post your .lss or your .hex.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, don't bother, You've helped enough, thanks alot :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why such a long delay between writing to PORTC and reading PINC?

 

That is always a tricky one.

 

Setting up for the "strobe" and then immediately reading is not likely to work well--AVR will be too fast for inbred capacitance and such.  Yet certainly 100ms for each column is way overkill--takes 1/2 second to read the whole keypad.

 

My approach is generally to reverse the order.  Each time slot:

 

-- Read the rows from the previous column strobe

-- Set up for new column strobe

 

Yes, there is a bit of a chicken-and-the-egg the first time around.

 

Generally, I might have a 2.5ms column strobe time, gather four sets of rows, and then enter the composite into the debounce routine.  Never a delay to be seen.  Upon request I'll dig out posted code.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.