C script for guiding a line follower - c

So for class I am trying to write a C script for a line follower robot. The robot has 3 sensors (ABC) which give logic 1 on black and logic 0 on white, A is on the left side, B in the middle and C on the right when looking straight down on the robot. It also has 2 motors, one on each side.
The board I am using is an Texas Instruments MSP-EXP430G2 and I am using the ports P1.0 - P1.7.
Now, I have literally 0 experience writing C scripts so all pointers are very much appreciated.
Here is the code.
# include "msp430G2553.h"
# include "stdio.h"
# include "math.h"
#define Both_On 1 // States
#define Left_On 2
#define Right_On 3
int main (void)
{
char STATE;
P1DIR|=0x0F; // Port1 four lower bits as OUTput, others as INput(0000 1111)
WDTCTL = WDTPW + WDTHOLD;// stop watch dog
STATE = Both_On; // Start here
char MASK1=0x10; //Sensor mask 0001 0000 (P1.0 - P1.7 from left to right)
char L; //Direction switch
while(1)
{
L = P1IN & MASK1; //Sensor value based on input-port
switch (STATE)
{
case Both_On:
P1OUT = 0x03;//Both motors on
puts("Both_On"); //for testing
if (L == 0x00 ){
P1OUT=0x01;//left motor on
STATE = Left_On;}
else if (L==0x10){
P1OUT=0x03;
STATE = Both_On;}
break;
case Left_On:
P1OUT = 0x01;//left motor on
puts("Left_on"); //for testing
if (L == 0x10 ){
P1OUT=0x03;//both motors on
STATE = Both_On;}
else if (L==0x00){
P1OUT= 0x02;
STATE = Right_On;}
break;
case Right_On:
P1OUT = 0x02;//right motor on
puts("Right_on"); //for testing
if (L == 0x10 ){
P1OUT=0x03;//both motors on
STATE = Both_On;}
else if (L==0x00){
P1OUT= 0x01;
STATE = Left_On;}
break;
break;
}//end of Switch
}// end of while
I think I've understood the method for switching from one active motor to another or both. The first 4 bits are reserved for the input from the sensors and the last 4 bits direct the motors. So P1OUT=0x03 basically means the output is 0000 0011 so the ports P1.6 and P1.7 are active and the motors wired to those ports would turn on.
I've been instructed to use an "L" variable as the direction switch. My problem is that I don't quite understand how this works.
I've been thinking that I would wire the B sensor to the port "L" takes it value from and then saying, if L==1 then both motors should be on and if L==0 then the state should change from "Left_on" to "Right_on" in a loop but this behavior doesn't feel very logical, I would want better detection.
Could I change the mask to be "MASK1=0x70" (0111) which would give me 3 ports to wire the sensors into, and guide the motors using for example:
else if (L==0x40){ //0100 only the left side sensor A is on black
P1OUT= 0x02; //0010 P1.6
STATE = Right_On;} // turn the right motor on to keep following the line
break;
As I said, all pointers and suggestions are highly appreciated.

Related

How can I create a bidirectional bus using a 18F4550?

Basically what Im trying to do its to use a single port of the PIC18F4550 as both inputs and outputs. Im going to connect a 7-segment-display to 7 pins of the port and with 4 pins of the same port. The four inputs are for introduce the numbers from 0 to 15 (F) in binary and the number in binary will represent in decimal in the display. Im using PIC C Compiler for the code.
Update: Following the first comment I modify the code and I think it is basically the same, I just read directly the input of the port B and use a switch-case in order to send the corresponding decimal number, also I added a default state so when I connected it should be a 0 in the display. Here it is the connection diagram, my teacher told me that I can ignore the logic gates but I'm not shure about that, in case I want to added I just need to use another port like port D to send a single high or low depending on how the port B is working.
Update 2: It finally work, it seems that the fact that I can ignore the logic gates it was partially true, the code was easier than I though, I just added a three port D high and low outputs to the EN and OE of both 74Ls244 and 74HC573 corresponding inputs so I can enable or disable depending on the port B state (output or input). Thank you all.
#include<18F4550.h>
#fuses XT, NOWDT, NOLVP, NOPROTECT, PUT
#use delay(clock = 4M, crystal = 8M)
#use fast_io(b)
void main(){
int8 INDSP;
int8 OUTDSP;
while(true){
SET_TRIS_B(0xFF);
INDSP = input_b()&0x0F;
switch(INDSP){
case 0b00000000:
OUTDSP = 0x3F;
break;
case 0b00000001:
OUTDSP = 0x0C;
break;
case 0b00000010:
OUTDSP = 0x76;
break;
case 0b00000011:
OUTDSP = 0x5E;
break;
case 0b00000100:
OUTDSP = 0x4D;
break;
case 0b00000101:
OUTDSP = 0x5B;
break;
case 0b00000110:
OUTDSP = 0x7B;
break;
case 0b00000111:
OUTDSP = 0x0E;
break;
case 0b00001000:
OUTDSP = 0x7F;
break;
case 0b00001001:
OUTDSP = 0x4F;
break;
case 0b00001010:
OUTDSP = 0x6F;
break;
case 0b00001011:
OUTDSP = 0x79;
break;
case 0b00001100:
OUTDSP = 0x33;
break;
case 0b00001101:
OUTDSP = 0x7C;
break;
case 0b00001110:
OUTDSP = 0x73;
break;
case 0b00001111:
OUTDSP = 0x63;
break;
DEFAULT:
OUTDSP = 0x3F;
break;
}
delay_ms(500);
SET_TRIS_B(0x00);
output_b(OUTDSP);
delay_ms(500);
}
}
Caveat: Not a total solution, but some suggestions ...
We can simplify your main as it has large amounts of replicated code:
void
main()
{
SET_TRIS_B(0b00001111);
DSPIN = input_b();
while (true) {
if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
DSPOUT = DSPIN;
else
DSPOUT = 0;
delay_ms(1000);
SET_TRIS_B(0b11111111);
if ((DSPOUT >= 0) && (DSPOUT <= 15))
output_b(DSPVALOR[DSPOUT]);
else
output_b(DSPVALOR[0]);
delay_ms(1000);
}
}
Now, given the top part of main:
SET_TRIS_B(0b00001111);
DSPIN = input_b();
The question I have is: should this be inside the while loop at the top???
Otherwise, there's no need for a loop as DSPIN and DSPOUT will remain constant.
UPDATE:
This is a total guess, but after cursorily looking at the datasheet ...
I think you're mixing up the value for the TRIS port. The second set_tris_b call should have 0b00000000 to set all bits for output (and not 0b11111111 as you have which sets all bits for input).
I'm not sure you can do this with a single 8 bit port. You need four bits for the input value. But, you need seven bits for output to the 7 segment display.
This adds up to more than 8 bits. So, I think you need two ports. Since you're using port "b", I presume there is a port "a".
You may be able to time division multiplex a given bit for input and output as you've done, but I think it's dicey and I don't know enough about the specifics of the 18F's ports to say for sure.
Here's refactored code that assumes a separate port "a":
void
main()
{
while (true) {
// set port B lower four bits for input
SET_TRIS_B(0b00001111);
// get input and mask off don't care bits
DSPIN = input_b();
DSPIN &= 0b00001111;
if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
DSPOUT = DSPIN;
else
DSPOUT = 0;
delay_ms(1000);
// set port A pins for output
SET_TRIS_A(0b00000000);
if ((DSPOUT >= 0) && (DSPOUT <= 15))
output_a(DSPVALOR[DSPOUT]);
else
output_a(DSPVALOR[0]);
delay_ms(1000);
}
}
But, if the 18F lets you change the tristate bits on the fly and you can connect both the input bit switches on bits 0-3 and the 7 segment output bits on bits 0-6, you can simply change all *_a calls into *_b calls.
UPDATE #2:
Upon further reflection [and, again, this is speculation], if the 18F allows one port to be switched back and forth repeatedly between input and output, the "duty cycle" in the above code is [probably] incorrect.
With 1000ms for both delays, the duty cycle is [only] 50% for output, so the 7 segment display will probably flicker badly.
That's because, when in tristate/input mode, the 7 segment display is not being driven with the correct segment mask/output value
The solution is to increase the duty cycle to (e.g.) 99.44% [the purity of Ivory Soap :-)]. So, most of the time, the port is in output mode. We only enter tristate/input mode briefly to sample the [DIP switch] input pins.
Here's a refactored version that keeps the port in output mode a high percentage of the time:
// NOTE: these may be need to be adjusted
enum {
INPUT_STABILIZE_DELAY = 1, // as short as possible
OUTPUT_STABILIZE_DELAY = 1, // as short as possible
OUTPUT_HOLD_DELAY = 100, // as long as possible
};
void
main()
{
while (true) {
// set port B lower four bits for input
SET_TRIS_B(0b00001111);
// allow port to stabilize
delay_ms(INPUT_STABILIZE_DELAY);
// get input and mask off don't care bits
DSPIN = input_b();
DSPIN &= 0b00001111;
// set output mode based on input
if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
DSPOUT = DSPIN;
else
DSPOUT = 0;
// set port B pins for output
SET_TRIS_B(0b00000000);
// allow tristate pins to stabilize
delay_ms(OUTPUT_STABILIZE_DELAY);
// output to 7 segment delay
output_b(DSPVALOR[DSPOUT]);
// ensure that port is in output mode 99.44% of the time
delay_ms(OUTPUT_HOLD_DELAY);
}
}

Embedded system: MSP430g2553 IAR programming ports/pins BASIC Input / Output syntax

To put it simply : How do I define and use ports / pins correctly in IAR EW with MSP430g2553?
Ill use example to clarify what I do not understand.
I have a simple state machine with 3 states. I want to program 3 pins for input and 2 pins for output.
Then, depending on inputs I manage state.
First, is this correct way of defining inputs / outputs ?
P1DIR |= BIT0 + BIT1; //pins 1.0 and 1.1 output
P1DIR &= ~BIT2 + BIT3 + BIT4; // pins 1.2 , 1.3, 1.4 input
The above seems to me fairly straightforward to use, however, bigger question is how do I reference input pins in code ? And how do I set output based on input?
To further my problem, here is my starting code for this state machine and I've put in pseudocode where I dont understand how to write syntax. Would be of great help if anyone could fill in the pseudocode and commentate a bit. I've looked many tutorials but I dont seem to get this simple thing from them.
# include "msp430g2553.h"
# include "stdio.h"
# include "math.h"
#define START 1
#define LEFT_ON 2
#define RIGHT_ON 3
char STATE;
main ()
{
P1DIR |= BIT0 + BIT1; //port 1.0 and 1.1 output
P1DIR &= ~BIT2 + BIT3 + BIT4; // port 1.2 , 1.3, 1.4 input
WDTCTL = WDTPW + WDTHOLD;
STATE =START;
while(1)
{
//STATE = START;
switch (STATE)
{
case START:
{
// Starting state I want both outputs to be set 1, I dont know how
set p1.0 to 1
set p1.1 to 1
puts("START");
//check inputs to switch state
if (1.2 == 1 & 1.3==0 & 1.4==0) {
STATE = RIGHT_ON;
} else if (1.2 == 0 & 1.3==0 & 1.4==1)) {
STATE = LEFT_ON;
}
break;
}
case LEFT_ON:
{
// Here I wish to to put 1.0 output to 1 and 1.1 output to 0
p1.0 set to 1
p1.1 set to 0
// now check if 1.3 is 1
if (1.3 == 1) {
STATE = START;
}
break;
}
case RIGHT_ON:
{
// Here I wish to to put 1.0 output to 0 and 1.1 output to 1
p1.0 set to 0
p1.1 set to 1
// now check if 1.3 is 1
if (1.3 == 1) {
STATE = START;
}
break;
}
}//end of Switch
}// end of while
}// end of main
First, is this correct way of defining inputs / outputs ?
I assume P1DIR is the correct data direction register (I don't know this particular MCU in detail), but apart from that: no, it isn't correct. First of all, use bitwise OR | not addition. They give the same result but + makes the code look strange and a bit harder to read. The average C programming book will tell you to do:
P1DIR |= BIT0 | BIT1;
Note that P1DIR |= ... will leave all pins currently set as output as they are. That may or may not be what you want.
To set a port pin active then simply do the same, SOME_PORT_REGISTER |= PIN_MASK;. Similarly, you can toggle a single pin with ^= which is bitwise XOR. Or set it to zero with &= ~(mask).
P1DIR &= ~BIT2 + BIT3 + BIT4; is wrong, ~ is a unary operator that only applies to one operand. Corrected code:
P1DIR &= ~(BIT2 | BIT3 | BIT4);
I've looked many tutorials
Most tutorials on the web are unfortunately quite bad. Start by reading a decent C programming book before anything else. Once you've learnt the basics of C, you can go look for tutorials.
For example this article about register access I wrote here, it assumed that the reader already knows C: How to access a hardware register from firmware?
As for full beginner tutorials, I think this one has better quality than most: Embedded Software in C for an ARM Cortex M, Jonathan W. Valvano and Ramesh Yerraballi. (It's Cortex M not MSP430 but the principles are very similar no matter MCU. The same author also has an older tutorial that used NXP HSC12 examples, which is another 16 bitter even more similar to MSP430.)

Multiple LEDs and using and input button

I am really stuck on part a and b for problem 1 below. I am really confused on how to change the multiply and divide functions to change pins/LED’s, using the << and >> functions instead.
Any help would be much appreciated. Thanks!
Multiple LEDs and using and input button
Modify the C program:
a. Instead of using the multiply and divide functions to change pins/LED’s, use the << and >> functions. References: Deitel and Deitel “C, How to Program and https://en.wikipedia.org/wiki/Operators_in_C_and_C
b. Change the clock frequency in the program to 1 MHz and make the on/off time of each LED .1 seconds. This should make the rotation visibly faster. (Remember to change the _XTAL_FREQ value since this is used for the __delay_ms() function built into XC8)
Devices:
Low Pin Count board (16F1829 on board) and 44-Pin Demo Board are both on same backboard. (You only use the 16F1829 for this lab.)
PICKIT 3 programmer with USB cable
MPLAB X (I used v3.00 but a different version may be on lab computers))
Microchip XC8 C Compiler User Manual
PIC16F1829 Data Sheet
PICkit 3 User’s Guide
Low Pin Count Board User Guide
“C How to Program” Deitel, Pearson/Prentice-Hall (Any edition)
Internet Browser Search Engine for research (Google, Bing, etc)
upload_2018-9-5_23-27-22.png
The code is below.
/*
LEDs on for approximately 0.5 sec.
PIC: 16F1829 Enhanced Mid-Level
Compiler: XC8 v1.34
IDE: MPLABX v3.00 */
#include <pic16f1829.h> //Not required but this is the reference used by "C" for names and location on uC
#include <htc.h> //refers on HiTech C, Microchip purchased HiTech
#define _XTAL_FREQ 4000000 //Used by the XC8 delay_ms(x) macro
#define switch PORTAbits.RA2 // Can use RA2 instead of PORTAbit.RA2 to define pin attached to switch
//instead of saying PORTAbits.RA2 each time
//config bits for the PIC16F1829
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=OFF, MCLRE=OFF, CP=OFF, CPD=OFF, BOREN=ON, CLKOUTEN=OFF, IESO=OFF, FCMEN=OFF
#pragma config WRT=OFF, PLLEN=OFF, STVREN=OFF, LVP=OFF
//Initialization subroutine
void initialize(void) {
ANSELC=0; //All pins of Port C are digital I/O
ANSA2=0; //switch pin, RA2, is digital IO
TRISA2 = 1; //switch is an input
TRISC = 0; //all pins of Port C are outputs
OSCCON = 0b01101000; // 4 MHz
}
unsigned char i1; //only need 4 bits to count to 16. unsigned character variable is 8 bits long
// Here is main(). There are many ways to do this 4-pin (LED) sequence
void main(void)
{
initialize();
i1=1; //Start the main program with the variable =1. Could have done this during its definition
while (1) //runs continuously until MCU is shut off
{
if (switch==1) //Button not pressed pin at 5V
{ i1=1; }
while (switch==1) //Button not pressed
{
PORTC=i1; //Note that writing to PORTC writes to LATC
__delay_ms(500);
i1=i1*2;
if (i1==16)
{ i1=1; }
}
if (switch==0) //Button pressed pin at ground
{ i1=8; }
while (switch==0) //Button pressed
{
PORTC=i1;
__delay_ms(500);
i1=i1/2;
if (i1==0)
{ i1=8; }
}
}
}
a. Instead of using the multiply and divide functions to change
pins/LED’s, use the << and >> functions. References: Deitel and Deitel
“C, How to Program and
https://en.wikipedia.org/wiki/Operators_in_C_and_C
Left shift value << n is integer multiplication of value by 2^n or value*(2^n)
Right shift value >> n is integer division of value by 2^n or value/(2^n))
When you have some var and you use one of the shift operators, you are taking the value of whatever var is and shifting the binary digits (bits) that represent it's value to the left or the right.
A basic example of this:
uint8_t var = 1; //0b00000001 in binary
var <<= 1; //var is now 0b00000010, that is 1*(2^1) or 2
var >>= 1; //var is now 0b00000001, that is 2/(2^1) or 1
There is a huge caveat for using the shift operator and that is that whenever you shift bits you are filling 0s in from the opposite direction that you are shifting so you have to pay attention to the integer size.
uint8_t var = 1;
var <<= 4; //var is now 0b00010000, 4 zeros filled in on the right
var = 1;
var <<= 8; //var is now 0b00000000, because 8 zeros were filled in on the right!
Now with regard to how you use this to manipulate the pins on a microcontroller, you would take some variable that increments or decrements and shift left or right by that variable and assign the resulting value to the register in the module that controls that pin, which in this case is the PORTx module. In your code that would look like this:
if (switch == 1) //Button not pressed pin at 5V
{
i1 = 0; //initialize to 0
}
while (switch == 1) //Button not pressed
{
PORTC = (1 << i1++); //set will set just one pin at a time, the first will be pin 0, the next pin 1, and so on
__delay_ms(500);
if (i1 == 8){
i1 = 0; //reset variable
}
}
if (switch == 0) //Button pressed pin at ground
{
i1 = 0; //initialize to 0
}
while (switch == 0) //Button pressed
{
PORTC = (0x80 >> i1++); //this will set 1 pin at a time, the first will be pin 7, the next will be pin 6, and so on
__delay_ms(500);
if (i1 == 8)
{
i1 = 0; //reset variable
}
}
b. Change the clock frequency in the program to 1 MHz and make the
on/off time of each LED .1 seconds. This should make the rotation
visibly faster. (Remember to change the _XTAL_FREQ value since this is
used for the __delay_ms() function built into XC8)
This portion of your code:
OSCCON = 0b01101000; // 4 MHz
Actually configures the frequency of the oscillator used by the microcontroller for its clock signal. However, it is important for you to know the source of that clock signal, which according to the datasheet is controlled by Configuration Word 1. This is set in the #pragma config FOSC=INTOSC portion of your code.
To obtain 1 MHz you will want to change that line to this:
OSCCON = 0b01011000; // 1 MHz
This is found in the OSCCON register description in the datasheet.
The __delay_ms function uses the _XTAL_FREQ to calculate a delay which is why you are being told to change this line of your code:
#define _XTAL_FREQ 4000000
To this
#define _XTAL_FREQ 1000000

Program Working on Old Device and New Device's Simulator but not on New Device

I'm hitting a roadblock in porting over a program I previously wrote for the PIC10F200 (see this related SO question). Turns out another component on the board needed to be swapped out for something that needed to be communicated with through I2C, so ergo, I'm porting the program to the PIC12LF1552.
This is how the program currently works (at least on the PIC10F200)
Program starts at IDLE (no lights on)
Press the button, the T0CKI pin (in the PIC12LF1552's case, RA2) is already pulled up to VDD (~3.3V) by an external pull-up resistor, the button is connected to ground and the pin, ergo pulling T0CKI's signal to LO.
TMR0 increments (supposedly)
After a time period where PORTAbits.RA2 settles, state increments
switch block moves to turn the external LED on, in the previous version of the circuit, this would also activate the IC this pin is connected to.
Rinse repeat for the other 3 states.
I have re-verified this functionality through using MPLAB X's simulator where I fired T0CKI (again, configured as RA2, again confirmed by the simulator) to HI and then to LO to engage the TMR0 code. state increments, and everybody is happy.
When I program the device using either MPLAB X connected to my PICkit3 or the included standalone programmer MPLAB IPE, the program does not work as intended. I have re-verified all connections, the programming port is connected as it should be. The button is attached the right pin. The test LED is attached to the right pin. For the time being we are not considering any I2C communication, I just want to see my status LED (RA4) toggle.
I know that now that I've transitioned to a midrange PIC, I can use the interrupt features, but for the time being I want to get what I know has worked on a much simpler device working on the current one.
My question then is, why doesn't this program work when programmed to the PIC12LF1552, but yet works on the PIC12LF1552 simulator AND its previous incarnation worked on the PIC10F200 (both programmed and simulated)?
Thanks in advance everyone!
The following is the entire program:
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#endif
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include <stdio.h>
#include <stdlib.h>
/******************************************************************************/
/* Defines */
/******************************************************************************/
//#define SYS_FREQ 16000000L
//#define FCY SYS_FREQ/4
#define _XTAL_FREQ 500000
__CONFIG
(
MCLRE_ON &
CP_OFF &
BOREN_OFF &
WDTE_OFF &
PWRTE_OFF &
FOSC_INTOSC
);
void main(void)
{
TRISA = 0b101111;
OPTION_REG = 0b01111111;
APFCONbits.SDSEL = 1;
unsigned char state = 0;
unsigned char count = 0;
while(1)
{
switch (state)
{
case 0: // IDLE/OFF
if (LATAbits.LATA4) LATAbits.LATA4 = 0;
break;
case 1: // ON
if (!LATAbits.LATA4) LATAbits.LATA4 = 1;
break;
case 2: // BLINK (slow)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(100);
break;
case 3: // BLINK (fast)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(50);
break;
case 4: // BEAT DETECT
LATAbits.LATA4 = LATAbits.LATA5;
break;
default:
state = 0;
break;
}
if (TMR0 > 0)
{
while (count < 20)
{
if (!PORTAbits.RA2) count = 0;
__delay_ms(10);
count++;
}
TMR0 = 0;
state++;
}
}
}
Some of the pins may be configured as Analog Inputs.
From the Datasheet for this device
"The operation of pin RA4 as analog is selected by setting the ANS3
bit in the ANSEL register which is the default set-ting after a
Power-on Reset".
If you do not set the ANSEL register the pin cannot be used as output as it is configured as an analog input.
This applies to all the pins that can be A/D inputs.
I do not see any configuration bit setup in your code.
Setting ANSEL and ANSELH to 0 should do the trick.
According to the this documentation , on page 93 about the ANSELA register
"The ANSELA bits default to the Analog mode after Reset. To use any
pins as digital general purpose or peripheral inputs, the
corresponding ANSEL bits must be initialized to ‘0’ by user software."
If you don't plan to use analog inputs, you may add something like ANSELA=0;

AVR Programming - How to read in consecutive button presses in C

Here's what I have to dp:
Consider an ATmega324A development board and a CSSE2010/CSSE7201 IO Board. Switches
S3 to S0 are connected to AVR port B pins 3 to 0. Push button B0 is connected to AVR port A
pin 0. LEDs L0 and L2 and connected to AVR port C pins 0 and 2 respectively.
LED L0 (red) is the “Locked” LED and should only be on when the lock is locked. LED L2
(green) is the “Unlocked” LED and should only be on when the lock is unlocked. The lock
initially starts in the locked state. The user enters the binary code for a digit on the switches (S3 to S0) and then presses and releases push button B0 to “enter” the first digit. The user then enters the binary code for the second digit on the switches and presses and releases push button B0 to “enter” the second digit. If the digits match the expected value (the last digit of your student number followed by the third digit of your student number) then the lock should be “unlocked”, otherwise it should stay in the locked state until the two digits are entered correctly.
Here is my code so far:
#include <avr/io.h>
/* Seven segment display values */
uint8_t seven_seg[16] = { 63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113};
int main(void) {
uint8_t digit;
uint8_t temp;
uint8_t digit2;
uint8_t code[2] = {6,3}
DDRA = 11111110; //port A is input (last bit)
DDRB = 0X00; //port B is input
DDRC = 0x0F; //port c is output
DDRD = 0XFF; //set port D to be output
while(1) {
/* Read in a digit from lower half of port C pins */
/* We read the whole byte and mask out upper bits */
PORTB = 1; //Led is red
clock = PINA & 00000001; //read in last bit of port A
temp = PINB & 0X0F; //read in lower half of port b
/* Checks to see the first digit is correct */
if(temp == code[0] && clock == 1) {
digit = temp;
PORTD = seven_seg[temp];
} else {
PORTD = 0;
}
}
I'm getting stuck at the point where I have to read in the second digit. Would I be doing this inside a nested loop of the first? Or how would I go about reading in two digits from my switches, which is clocked in each time from the press of a button?
To make a variable program that can be used for longer number sequences, simply use a loop. for(uint8_t i=0; i<NUMBER_OF_DIGITS; i++). The port reading needs to be inside the loop.
However, you cannot read buttons the way you do. All buttons have an electro-mechanical signal bounce, which you need to filter out to prevent false readings. You must do this on any kind of embedded system.
The simplest way to do this is to sample the button once, save the result, wait a few milliseconds, then sample it again. If the samples compare equal, accept it as result (pressed or not pressed).
Alternatively, you can trigger an interrupt on the edge of the button signal, from there start a timer, and then when the timer runs out, read the port.
More advanced methods use some form of median filters.
So if i get you right you wanna do something like this
Start:
Wait for pushbutton
Wait for first digit
Wait for pushbutton
Wait for second digit
If digits they are the same
Turn off Red LED
Turn on Green LED
Else
Goto start
Can you confirm this? It is always a good thing to do your code in pseudo first. It gives very good overview of what you want to do.

Resources