Can't read PC0 and PC1

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

Hi Guys,

 

I'm stuck with a problem. As in the title I can't read the PC0 and PC1 register when they are set as inputs. I am trying to read an 8 button array.

 

Here's what I know:

 

- The pins on the microcontroller are definitely being pulled low by the external button circuitry. (Logic low on pin is fine)

- The code relating to the reading of the pins works when pins from the B register are used instead of the C register.

 

Here's my code, it's for stepper driver control. The buttons currently stop and start a repeating square wave, the PC inputs are supposed to control the ramping routine. I used arrays to hold variables for the debouncing and everything seems to work except the above problem.


#define F_CPU 8000000
#include <avr/io.h>				// this is always included in AVR programs
#include <avr/interrupt.h>
#include <util/delay.h>



/*************************
~~Interrupt Service Routines~~
This ISR increments a tick that is counted in the code
for task orchestration.

 *************************/ 

volatile uint8_t tick = 0;

    ISR(TIMER1_COMPA_vect) {
	    tick += 1;
    }
    
	
	

int main(void)
{
	
/*************************
~~Inputs and Outputs~~

 *************************/ 	
	/*
	B0 = Input => 
	B1 = Input => 
	B2 = Input =>  
	B3 = Input => 
	B4 = Input => 
	B5 = Input => 
	
	C0 = Input => 
	C1 = Input =>
	
	C4 = Output => Enable
	C5 = Output => Direction
	D0 = Output => Step
	D1 = Output => 
	
	 */ 

/*************************
~~Microcontroller Setup~~

 *************************/ 
	MCUCR |= (1 << PUD); // Set inputs to high impedance 
	
	UCSR0B &= ~(1 << RXEN0);
	UCSR0B &= ~(1 << TXEN0);// Turn off USART
	
	PORTB = (1 << PINB0) | (1 << PINB1) | (1 << PINB2) | (1 << PINB3) | (1 << PINB4) | (1 << PINB5);
	DDRB =  0; //(1 << PINB2) | (1 << PINB3) | (1 << PINB4);// | (1 << PINB6) | (1 << PINB7); 1 = output
	
	PORTC = (1 << PINC0) | (1 << PINC1);
	DDRC = 0;//(1 << PINC0) | (1 << PINC1) | (1 << PINC2) | (1 << PINC3);
	
	PORTD = 0; //(1 << PIND2) | (1 << PIND3) | (1 << PIND4) | (1 << PIND5) | (1 << PIND6) | (1 << PIND7);
	DDRD = (1 << PIND0) | (1 << PIND1);

	ADCSRA = 0; // Turn off ADC circuity in case it is interfering with C register input reading

    TCCR1B = 0;
    TCCR1B = 0;
	OCR1A = 399; // set OCR1A value based on. OCR1A = (Clock frequency / (prescaler * target frequency)) - 1
	// 79 = 10us tick, 399 = 50us tick,	7999 = 1ms tick
	// CS10 no prescaler used.
	// WGM12 is the clear timer on compare enable.
    TCCR1B |= (1 << CS10 ) | (1 << WGM12); 
    TIMSK1 |= (1 << OCIE1A); // Enable output compare register.
   
    sei(); // Globally enable interrupts
    //cli() to disable interrupts
 
   
/*************************
~~Code Variables~~
Variables used in the code are initialized heres

 *************************/     

	int stepTimer = 0; // Counter for the step incrementing task
	int Bin[8] = {0}; // Button inputs for debouncing
	int Blast[8] = {1}; // Stored Button input states
	int BT[8] = {0}; // Keeps track of how many times a button is seen HIGH
	uint8_t timeValue = 10; // Minimum debouncing delay
	bool run = true; // Links debouncing and Output Wave task
	bool rampUp = false; // Links debouncing and ramping task
	bool rampDown = false; // Links debouncing and ramping task
	//bool stepState = true;
	//bool passArr[7] = {0};
	int stepDel = 255;
	

    while (1)
    {
		
/*************************
~~Tick~~
The tick value is incremented by the ISR. Task counters are incremented by the 
tick value before it is reset. The tasks are effectively driven by a prescaler
of the devices clock

 *************************/ 		
	    if(tick > 0)
	    {
			// put counting routines here
			stepTimer+= tick;
			
			tick = 0;
		}
		
// ******** This code will only execute when the task counter has reached a value ********
		if(stepTimer >= stepDel) 
	{
		if( run == 1)
		{
			
/*************************
~~Ramping routines~~


 *************************/ 		
			// code for ramping up delay	
			if (rampUp == true)
			{
				stepDel -= 10;
				if (stepDel <= 40) 
				{
					stepDel = 40;
					rampUp = false;
				}
				
			}
		
			// code for ramping down delay	
			if (rampDown == true)
			{
				stepDel += 10;
				if (stepDel >= 255)
				{
					stepDel = 255;
					rampDown = false;
				}
				
			}
		PIND |= (1<<0);// These set the motor to step
		PIND |= (1<<1);
	//	PINC |= (1<<4);
	//	PINC |= (1<<5);
	
	}
	


			stepTimer = 0;
	}
	
/*************************
~~Debouncing Routines~~
The next task reads though the devices inputs and debounces them
since they are mechanical switches driving the input register values
 *************************/ 

	// Input B0
	Bin[0] = PINB &(1 << 0);
	if (Blast[0] != Bin[0])
	BT[0]++;
	if(BT[0] > timeValue)
	{
		if(Bin[0] == 0)
			{
				run = true;
			}
		
		Blast[0] = Bin[0];
	}
	if(Bin[1] == 1)
	BT[1] = 0;
	
	// Input B1
	Bin[1] = PINB &(1 << 1);
	if (Blast[1] != Bin[1])
	BT[1]++;
	if(BT[1] > timeValue)
	{
		if(Bin[1] == 0)
			{
				run = true;
			}
		
		Blast[1] = Bin[1];
	}
	if(Bin[1] == 1)
	BT[1] = 0;
	
	// Input B2
		Bin[2] = PINB &(1 << 2);
		if (Blast[2] != Bin[2])
		BT[2]++;
		if(BT[2] > timeValue)
		{
			if(Bin[2] == 0)
			{
				run = false;
			}
	
			Blast[2] = Bin[2];
		}
		if(Bin[2] == 1)
		BT[2] = 0;
		
	// Input B3	
		Bin[3] = PINB &(1 << 3);
		if (Blast[3] != Bin[3])
		BT[3]++;
		if(BT[3] > timeValue)
		{
			if(Bin[3] == 0)
			{
				run = false;
			}
			
			Blast[3] = Bin[3];
		}
		if(Bin[3] == 1)
		BT[3] = 0;
		
	// Input B4
		Bin[4] = PINB &(1 << 4);
		if (Blast[4] != Bin[4])
		BT[4]++;
		if(BT[4] > timeValue)
		{
			if(Bin[4] == 0)
			{
				run = false;
			}
			
			Blast[4] = Bin[4];
		}
		if(Bin[4] == 1)
		BT[4] = 0;
		
	// Input B5	
		Bin[5] = PINB &(1 << 5);
		if (Blast[5] != Bin[5])
		BT[5]++;
		if(BT[5] > timeValue)
		{
			if(Bin[5] == 0)
			{
				run = false;
			}
			
			Blast[5] = Bin[5];
		}
		if(Bin[5] == 1)
		BT[5] = 0;
		
	// Input C0
		Bin[6] = PINC &(1 << 0);
		//Bin[6] = PINB &(1 << 4);
		if (Blast[6] != Bin[6])
		BT[6]++;
		if(BT[6] > timeValue)
		{
			if(Bin[6] == 0)
			{
				rampDown = false;
				rampUp = true;
			}
			
			Blast[6] = Bin[6];
		}
		if(Bin[6] == 1)
		BT[6] = 0;
		
	// Input C1
		Bin[7] = PINC &(1 << 1);
		//Bin[7] = PINB &(1 << 5);
		if (Blast[7] != Bin[7])
		BT[7]++;
		if(BT[7] > timeValue)
		{
			if(Bin[7] == 0)
			{
					rampDown = true;
					rampUp = false;
			}
	
			Blast[7] = Bin[7];
		}
		if(Bin[7] == 1)
		BT[7] = 0;




    }
    
    }

 

 

I'm stumped. Any ideas?

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

What AVR are you using?

 

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

Last Edited: Wed. May 15, 2019 - 07:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, it's an ATmega328p.

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

I'm not seeing anything in the code, could it be a h/w problem?   Mis-wiring perhaps.

How sure are you of loading the code with the portc polling, could you be loading the portb poling code by mistake?

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

Is this the  'haven't connected supply voltage to AVCC pin' ?

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

MrKendo wrote:
Is this the  'haven't connected supply voltage to AVCC pin' ?

+1

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.

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

MrKendo wrote:

 

Here's my code, it's for stepper driver control. The buttons currently stop and start

+1

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

theusch wrote:
MrKendo wrote:

Is this the  'haven't connected supply voltage to AVCC pin' ?

 

+1

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

Muffins wrote:
As in the title I can't read the PC0 and PC1 register when they are set as inputs.
Define "can't read". Clearly it does read something - are you saying it's stuck 0 or stuck 1 or showing random reading unrelated to button state or what? "can't read" isn't really a fault report.

 

Also can you say how you are observing this? Is this a watch window on BT[6]/BT[7] in a debugWire debugger or something else?

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

Hi guys, sorry for the delay.

 

I have the chip setup in a PCB I designed. I have checked the routing and the connections and it's good. The board just adds some protection diodes and resistors to each pin, there is no difference from the C0 and C1 pins to the other pins, they have the same circuitry. I have also uploaded the code to a separate 328p and the same problem occurs.

 

Jim, how would I load the port polling code incorrectly? What do you mean by this?

 

The supply voltage is connected to and present at the AVCC pin. Checked with my scope to confirm.

 

clawson,

 

I have my scope setup on my circuit, watching the signal alternate between low and high and the chip not responding to this. The same code on different pins works fine. My setup is very basic. I have been plugging the chips into an arduino UNO board to upload code to them, then removing them from that board and inserting them into my board.

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

How is your code working for Pin B? 

Last Edited: Sat. May 18, 2019 - 07:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Muffins wrote:

	Bin[7] = PINC &(1 << 1);

 

even if PC1 goes HIGH this statement will not be true, because (1<<1) != 1 

 

Muffins wrote:

if(Bin[7] == 1)

 

and similarly, The following statement will always be true

Muffins wrote:

Bin[7] = PINC &(1 << 1);
//Bin[7] = PINB &(1 << 5);
if (Blast[7] != Bin[7])

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

I'm testing some code now. With C0 and C1 being used as inputs. I don't seem to have trouble using them as inputs now.

 

#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
	
	MCUCR |= (1 << PUD); 
	DDRB =  (1 << PINB5);
	
	PORTC = (1 << PINC0) | (1 << PINC1) | (1 << PINC2);
	DDRC = 0;//(1 << PINC0) | (1 << PINC1) | (1 << PINC2) | (1 << PINC3);
	
	int  x = 0;
	
	
	
    /* Replace with your application code */
    while (1) 
    {
		
		x = PINC &(1 << 0);
		
		if (x )
			{
				PINB |= (1<<5);
			}
		else
			{
				PINB &= ~(1<<5);
			}
		
		
		
		_delay_ms(1000);
    }
}

 

When you say, " even if PC1 goes HIGH this statement will not be true, because (1<<1) != 1  "

 

I thought I would be capturing the state of that bit. What am I actually reading when I do that? The value for the whole register?

 

 

Why will this always be true?

Bin[7] = PINC &(1 << 1);

if (Blast[7] != Bin[7])

 

 

 

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

I think what he means is that the later:

		if(Bin[7] == 1)
		BT[7] = 0;

will never be true. (1 << 1) is 2 not 1. So Bin[7] will be either 0 or 2 so will never be 1.

 

BTW here's a useful "trick". If you have any value that is either 0 or any numeric value like 4, 17, 32, 64, 65 or whatever you can turn it into 0 / 1 with a double application of !. Something like:

x = 16;
x = !!x;

Now x is 1. So it effectively converts an int to a bool.

 

In this example !16 is 0 and !0 is 1. That's how it works.

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

Could I read the pin and convert it at the same time?

 

Maybe something like this:

Bin[6] = !!(PINC &(1 << 2));

 

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

Yes that is a very common thing to do. In fact if you look at the source of the Linux kernel you will find this going on a lot. Another way to do it is by implicit conversion. If I write something like:

typedef struct {
    int b0:1;
    int b1:1;
    int b2:1;
    int b3:1;
    int b4:1;
    int b5:1;
    int b6:1;
    int b7:1;
} bits_t;

bits_t mybits;

mybits.b2 = PINC & (1 << 2);

then ".b2" is only one bit (that's what :1 means) so when C reads PINC and does the bit 2 mask on it then it will come up with an integer result of either 0x00 or 0x04 depending on whether the bit is set or not. But 4 into 1 does not go! So when it assigns to the 1 bit variable it will do an implicit truncation during which 0 maps to 0 and any non-0 value maps to 1.

 

So this is another way to achieve the same thing.

 

BTW if you have 8 binary variables you want "fast access" to on an AVR then most modern AVRs have a "spare" register called GPIOR0 that can be used for this (because it is placed at such a low IO address that SBI and CBI opcodes can be used). So you can (using the same kind of typedef I showed above) do something like:

#define mybits (*(volatile bits_t *)&GPIOR0)

For example (built for mega328P):

#include <avr/io.h>

typedef struct {
	int b0:1;
	int b1:1;
	int b2:1;
	int b3:1;
	int b4:1;
	int b5:1;
	int b6:1;
	int b7:1;
} bits_t;

#define mybits (*(volatile bits_t *)&GPIOR0)

int main(void)
{
	while(1)
	{
		mybits.b3 = 1;
		mybits.b7 = 0;
	}
}
	while(1)
	{
		mybits.b3 = 1;
  80:	f3 9a       	sbi	0x1e, 3	; 30
		mybits.b7 = 0;
  82:	f7 98       	cbi	0x1e, 7	; 30

So the setting and clearing of the bits comes down to one opcode to SBI (set bit) or CBI (clear bit). This is VERY efficient code!!

As most AVR only have one GPIOR0 in range then save your 8 most important binary variables to use this technique on.

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

clawson wrote:

then ".b2" is only one bit (that's what :1 means) so when C reads PINC and does the bit 2 mask on it then it will come up with an integer result of either 0x00 or 0x04 depending on whether the bit is set or not. But 4 into 1 does not go! So when it assigns to the 1 bit variable it will do an implicit truncation during which 0 maps to 0 and any non-0 value maps to 1.

 

Really neat idea Using GPIOR0 like this.

Just need to coment on the above statement, if defined as int b2 : 1, it won't map any non zero value to 1.

If you want it to map any non zero value to 1 then you either still need to use !!, or  for C99 onwards use _Bool (or bool with <stdbool.h>) ie.

 

#include <stdbool.h>

typedef struct {
	bool b0:1;
	bool b1:1;
	bool b2:1;
	bool b3:1;
	bool b4:1;
	bool b5:1;
	bool b6:1;
	bool b7:1;
} bits_t;

Also, for benefit of others, plain int is a bit iffy with bitfields because, due to a strange quirk, a plain int in bitfield context can be either signed or unisgned (which of couse isn't the case anywhere else, where plain int is most definitely signed).

So always best with bitfields to be explicit and say signed int or unsigned int. For 1 bit value of 0 or 1 you want unsigned int.

Alternatively,  gcc will allow use of uint8_t.

 

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

Hi guys, sorry for the late reply.

 

Thank you for the help and thank you clawson for the explanation.

 

I have managed to fix the errors in my code and everything is working perfectly.