1
votes

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

  1. 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; }
        }
    }
}  
1
Please start by formatting your code. Empty lines and indentation might not matter to the compiler, but it does for humans attempting to read your code.Some programmer dude
Here is the multiply code: i1=i1*2; Here is the divide code: i1=i1/2; completely lost on where to start on changing this to use << and >> functions to change pins/LED’s.kittylickens
Also please take some time to read the help pages, take the SO tour and read about how to ask good questions. Lastly please read this question checklist.Some programmer dude
Please edit your question to add info, instead of hiding it in comments.Yunnosch
I believe i grasp this now. thanks for being patient with me as learn this. So i1=i1*2 would then be i1=i1<<1 (the value of i1 would be shifted to the left in the binary code by 1 therefore multiplying it by 2.) then i1=i1/2 would be i1=i1>>1 (the value of i1 would be shifted to the right in the binary code by 1 therefore dividing it by 2.)kittylickens

1 Answers

1
votes

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