简体   繁体   中英

How to implement arduino Uno shiftOut() in AVR C?

I am trying to control an 8x8 led matrix using shift register 74hc595. In normal Arduino code, we use the shiftOut() function to write to the dataPin, but what I am having trouble trying out the same thing in AVR C. The only issue I am having is how to send the data to only the dataPin of the shift register, because if I use PORTB |= data everything in the port gets affected.

This is my code so far -

#define F_CPU 20000000L
#include <avr/io.h>
#include <avr/delay.h>

#define latchPinColumn 3
#define latchPinRow 2
#define clockPin 4
#define dataPin 5

//for looping
byte i, j;

//storing data
byte dataToSendColumn;
byte dataToSendRow;

int main()
{
  //enabling output pins
  DDRB |= (1 << dataPin);
  DDRB |= (1 << clockPin);
  DDRB |= (1 << latchPinColumn);
  DDRB |= (1 << latchPinRow);
  
  PORTB = 0x00; //setting everything to low
  
  while(1)
  {
    for(i=0; i<8; i++)
    {
      for(j=0; j<8; j++)
      {
        dataToSendColumn = (1<<i);
        dataToSendRow = (1<<j);
        
        PORTB = 0x00;   //setting everything to low
        shiftOut(dataPin, clockPin, dataToSendColumn); //controlling the column
        PORTB |= (1 << latchPinColumn); //setting latch pin for led column to high
        PORTB ^= (1 << latchPinColumn); //setting latch pin for led column to low
        shiftOut(dataPin, clockPin, dataToSendRow); //controlling the row
        PORTB |= (1 << latchPinRow); //setting latch pin for led row to high
        PORTB ^= (1 << latchPinRow); //setting latch pin for led column to low
        
      }
    }
  }
}

void shiftOut(int dataP, int clock, int val)
{
  //performing shiftOut in LSBFIRST method
  for(i=0; i<8; i++)
  {
    data = val & 0b00000001;
    PORTB |= data;
    PORTB ^= (1^=clock);
  }
}

how arduino implement ShiftOut

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
    uint8_t i;

    for (i = 0; i < 8; i++)  {
        if (bitOrder == LSBFIRST)
            digitalWrite(dataPin, !!(val & (1 << i)) );
        else    
            digitalWrite(dataPin, !!(val & (1 << (7 - i))));
            
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);        
    }
}

some note to helpe you in explanition of the code

  1. first of all the type of uint8_t is just char Type in some place it there is somthing like this typedef char uint8_t
  2. as Showen in function signature it Take 4 char as an argument
    • data pin the pin number that you conect the data on it
    • clock pin the pin number that you conect the clock on it
    • bit Order To choose which bit go first ( least significant bit go first or most significant bit go first ) and there are some def.netions you could use For that #define LSBFIRST 0 and #define MSBFIRST 1
    • Val the data you like shift it out on pins
  3. the data Val is a char Type and Char type is just an 8 bit so you will loop 8 time to get each bit in val
  4. 1<<i this is shift left operator it just will creat a musk of bits For examble if i is equal 5 than that will creat binary like 0b00100000 and if i is equal to 2 that will creat binary bits like 0b00000100
  5. val & (1<<i) ... the operator & is a bitwise and opertor this expration will give a non zero values if the i'th bit in val is 1 and will give zero if the i'th bit in val is Zero
  6. the data will writen in shift Register if the clock pin go from High to low

How to implrment it with your AVR

the implementation in AVR will be much similar to arduino implementation with a little bit difference... you should notice that in arduino you access the pin just with a pin number and inside the Function used by arduino this pin number will be decoded into port Number ( PORTA,PORTB,..etc ) and bit Number inside that port

important information you need to know that the port is just an Regester in memory and that register is 8 bit width and you code access that Register with Char pointer

the AVR Code FOR Shift out

// helper macros to make pin HIgh or low
#define  SET_PIN(port,pinNumber)  ( (port) |= (1<<pinNumber))
#define  CLEAR_PIN(port,pinNumber) ( (port) &=~(1<<pinNumber) )
// defention for Bits order
#define LSBFIRST 0
#define MSBFIRST 1

// pin information
typedef struct {
    volatile unsigned char * Port;
    char NUmber;
}Pin;

// function implementaiton
void shiftOut(Pin dataPin, Pin clockPin, char bitOrder, char val)
{
    char i;

    for (i = 0; i < 8; i++)  {
        if (bitOrder == LSBFIRST){
            (val & (1 << i))?SET_PIN(*dataPin.Port,dataPin.NUmber):CLEAR_PIN(*dataPin.Port,dataPin.NUmber);
        }
        else{
            (val & (1 << (7 - i)))?SET_PIN(*dataPin.Port,dataPin.NUmber):CLEAR_PIN(*dataPin.Port,dataPin.NUmber);
        }

        // make a clockpin go from high to low
        SET_PIN(*clockPin.Port,clockPin.NUmber);
        CLEAR_PIN(*clockPin.Port,clockPin.NUmber);
    }
}

and use it inside main like this

void main(){
   //code ...
   // init section 
    Pin data = {&PORTB,4};
    Pin clock= {&PORTB,5};
    // make it output
    DDRB |=1<<4;
    DDRB |=1<<5;        
    //code ...
    while(1){
        // code ..
        // use when you need
        shiftOut(data,clock,LSBFIRST,9); // this will shift out 9(0b00001001) low bit will go first
        // code ...
    }   
        
}

this is a quick way... you Could make it better if you have your own GPIO Drivers (General Purpose Input Output Driver) For set and clear PIns and make them input or output

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM