繁体   English   中英

如何在 AVR C 中实现 arduino Uno shiftOut()?

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

我正在尝试使用移位寄存器 74hc595 控制 8x8 LED 矩阵。 在正常的 Arduino 代码中,我们使用shiftOut() function 写入 dataPin,但我在 AVR C 中尝试同样的事情时遇到了麻烦。我遇到的唯一问题是如何将数据仅发送到 dataPin移位寄存器,因为如果我使用PORTB |= data ,端口中的所有内容都会受到影响。

到目前为止,这是我的代码 -

#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);
  }
}

arduino 如何实现 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);        
    }
}

一些注释可以帮助您解释代码

  1. 首先, uint8_t的类型只是在某个地方的char类型,它有类似typedef char uint8_t的东西
  2. 如 function签名所示,它以 4 个字符作为参数
    • data pin你连接数据的pin号
    • clock pin你连接时钟的引脚号
    • bit Order要选择哪个位 go 首先(最低有效位 go 第一个或最高有效位 go 首先),并且您可以使用一些 def.netions 为此#define LSBFIRST 0#define MSBFIRST 1
    • Val您喜欢的数据将其移出引脚
  3. 数据Val是一个char类型,而 Char 类型只是一个8 位,所以你将循环 8 次以获取val中的每一位
  4. 1<<i这是左移运算符,它只会创建一个位的麝香例如,如果i is equal 5 ,则将创建二进制,如0b00100000 ,如果i is equal to 2 ,将创建二进制位,如0b00000100
  5. val & (1<<i) ... 运算符&按位运算符,如果val中的第 i 位为1 ,则此表达式将给出非零值,如果val中的第 i 位为零
  6. 如果时钟引脚 go 从高到低,数据将写入移位寄存器

如何用你的 AVR 实现它

AVR 中的实现与 arduino 的实现非常相似,只是有一点点不同……您应该注意到,在 arduino 中,您只需使用一个引脚号访问该引脚,而在 arduino 使用的 Function 内部,此引脚号将被解码为端口号( PORTA,PORTB,..etc ) 和该端口内的位号

重要信息,您需要知道该端口只是 memory 中的一个 Register,并且该寄存器是 8 位宽,您可以使用Char pointer访问该 Register

AVR 代码 FOR 移出

// 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);
    }
}

并像这样在 main 中使用它

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 ...
    }   
        
}

这是一个快速的方法......如果你有自己的 GPIO 驱动程序(通用输入 Output 驱动程序)你可以做得更好,用于设置和清除 PINS 并使它们输入或 output

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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