如何在 AVR C 中实现 arduino Uno shiftOut()?
How to implement arduino Uno shiftOut() in AVR C?
我正在尝试使用移位寄存器 74hc595 控制 8x8 LED 矩阵。在普通的 Arduino 代码中,我们使用 shiftOut()
函数写入 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);
}
}
一些注释可以帮助您解释代码
- 首先
uint8_t
的类型只是 char
在某个地方输入它有这样的东西 typedef char uint8_t
- 如 函数签名中所示 它以 4 个字符作为参数
data pin
你连接数据的pin码
clock pin
你连接时钟的pin码
bit Order
要选择哪个位先行( 最低有效位先行或最高有效位先行)并且您可以使用一些定义为此 #define LSBFIRST 0
和#define MSBFIRST 1
Val
你喜欢的数据在pin上移出
- 数据
Val
是一个 char
类型而 Char 类型只是一个 8 位 所以你将循环 8 次以获取 char
中的每一位=24=]
1<<i
这是 左移运算符 它只会创建一个位的麝香例如如果 i is equal 5
比那将创建像 [=27 这样的二进制文件=] 并且如果 i is equal to 2
将创建像 0b00000100
这样的二进制位
val & (1<<i)
... 运算符 &
是 按位运算符 如果第 i 个位在val
是 1
并且如果 val
中的第 i 位是零 则给出零
- 如果时钟引脚从高电平变为低电平,数据将写入移位寄存器
如何用你的 AVR 实现它
AVR 中的实现与 arduino 的实现非常相似,但略有不同……您应该注意到,在 arduino 中,您只需使用 pin 编号 访问 pin 和在 arduino 使用的函数中,这个 pin number 将被解码为 port Number (PORTA,PORTB,..etc) 和 位号 在那个端口
重要信息您需要知道该端口只是内存中的寄存器,并且该寄存器是 8 位宽,您可以通过代码访问该寄存器Char pointer
移出的 AVR 代码
// 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 驱动程序(通用输入输出驱动程序),你可以做得更好,用于设置和清除 PINS 并使它们成为输入或输出
我正在尝试使用移位寄存器 74hc595 控制 8x8 LED 矩阵。在普通的 Arduino 代码中,我们使用 shiftOut()
函数写入 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);
}
}
一些注释可以帮助您解释代码
- 首先
uint8_t
的类型只是char
在某个地方输入它有这样的东西typedef char uint8_t
- 如 函数签名中所示 它以 4 个字符作为参数
data pin
你连接数据的pin码clock pin
你连接时钟的pin码bit Order
要选择哪个位先行( 最低有效位先行或最高有效位先行)并且您可以使用一些定义为此#define LSBFIRST 0
和#define MSBFIRST 1
Val
你喜欢的数据在pin上移出
- 数据
Val
是一个char
类型而 Char 类型只是一个 8 位 所以你将循环 8 次以获取char
中的每一位=24=] 1<<i
这是 左移运算符 它只会创建一个位的麝香例如如果i is equal 5
比那将创建像 [=27 这样的二进制文件=] 并且如果i is equal to 2
将创建像0b00000100
这样的二进制位
val & (1<<i)
... 运算符&
是 按位运算符 如果第 i 个位在val
是1
并且如果val
中的第 i 位是零 则给出零
- 如果时钟引脚从高电平变为低电平,数据将写入移位寄存器
如何用你的 AVR 实现它
AVR 中的实现与 arduino 的实现非常相似,但略有不同……您应该注意到,在 arduino 中,您只需使用 pin 编号 访问 pin 和在 arduino 使用的函数中,这个 pin number 将被解码为 port Number (PORTA,PORTB,..etc) 和 位号 在那个端口
重要信息您需要知道该端口只是内存中的寄存器,并且该寄存器是 8 位宽,您可以通过代码访问该寄存器Char pointer
移出的 AVR 代码
// 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 驱动程序(通用输入输出驱动程序),你可以做得更好,用于设置和清除 PINS 并使它们成为输入或输出