侧边栏壁纸
博主头像
komi

Bona Fides

  • 累计撰写 18 篇文章
  • 累计创建 36 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

wiring_shift.c 移位操作

komi
2025-10-07 / 0 评论 / 3 阅读 / 1,043 字

自己慢慢搭面包板电路的同时也在学Arduino
无意间从Arduino15这个路径发现些板子内置的代码 因为自己有一个SAMD的板子 所以文件夹中两种架构
AVR (Uno、Nano常规板子) SAMD (MKR低功耗点的板子)
image
其中wiring_shift.c里面只有两个函数 想看看主要是做什么的

AVR

/*
  wiring_shift.c - shiftOut() function
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2005-2006 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

#include "wiring_private.h"

uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
	uint8_t value = 0;
	uint8_t i;

	for (i = 0; i < 8; ++i) {
		digitalWrite(clockPin, HIGH);
		if (bitOrder == LSBFIRST)
			value |= digitalRead(dataPin) << i;
		else
			value |= digitalRead(dataPin) << (7 - i);
		digitalWrite(clockPin, LOW);
	}
	return value;
}

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);
			val >>= 1;
		} else {	
			digitalWrite(dataPin, (val & 128) != 0);
			val <<= 1;
		}
			
		digitalWrite(clockPin, HIGH);
		digitalWrite(clockPin, LOW);		
	}
}

这里两个函数基本上是利用给定的数据引脚和时钟引脚 做读取和写入操作

shiftIn() 依靠digitalWrite()给时钟引脚拉高/拉低电平之间来从数据引脚读取 根据LSBFIRST/MSBFIRST 会依次从最低位/最高位利用或运算做补位

shiftOut() 直接对val进行位移 如果是LSBFIRST只读取最低位(&1 00000001 与运算) 通过digitalWrite直接写入数据引脚 之后右移1位(/2) 再去读最低位 而MSBFIRST是只读取最高位(&128 10000000 与运算) 同样用digitalWrite写入 之后左移1位(*2) 再去读最高位 所有这8位都结束后将时钟引脚拉高后立刻拉低 形成一种脉冲来提示设备有数据写入

SAMD

/*
  Copyright (c) 2014 Arduino.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <stdint.h>
#include <Arduino.h>
#include "wiring_private.h"

#ifdef __cplusplus
extern "C"{
#endif

uint8_t shiftIn( pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder )
{
  uint8_t value = 0 ;
  uint8_t i ;

  for ( i=0 ; i < 8 ; ++i )
  {
    digitalWrite( ulClockPin, HIGH ) ;

    if ( ulBitOrder == LSBFIRST )
    {
      value |= digitalRead( ulDataPin ) << i ;
    }
    else
    {
      value |= digitalRead( ulDataPin ) << (7 - i) ;
    }

    digitalWrite( ulClockPin, LOW ) ;
  }

  return value ;
}

void shiftOut( pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder, uint8_t ulVal )
{
  uint8_t i ;

  for ( i=0 ; i < 8 ; i++ )
  {
    if ( ulBitOrder == LSBFIRST )
    {
      digitalWrite( ulDataPin, !!(ulVal & (1 << i)) ) ;
    }
    else
    {
      digitalWrite( ulDataPin, !!(ulVal & (1 << (7 - i))) ) ;
    }

    digitalWrite( ulClockPin, HIGH ) ;
    digitalWrite( ulClockPin, LOW ) ;
  }
}

#ifdef __cplusplus
} // extern "C"
#endif

能发现从代码功能上和AVR板子上大体相同 用extern C防止编译器命名重整

可以发现 无论是shiftIn还算shiftOut 参数的类型都要更严苛

packages\arduino\hardware\samd\1.8.14\cores\arduino\api\Common.h

#ifdef EXTENDED_PIN_MODE
// Platforms who want to declare more than 256 pins need to define EXTENDED_PIN_MODE globally
typedef uint32_t pin_size_t;
#else
typedef uint8_t pin_size_t;
#endif

typedef enum {
  LSBFIRST = 0,
  MSBFIRST = 1,
} BitOrder;

和AVR稍显不同的地方在shiftOut() 之前在AVR板子上是直接对val进行位移 而SAMD是直接通过循环i的位移来ulVal通过与运算写入 !!(强制转换为布尔值) 这里也是为了确保读取的结果只限定位0和1

结语

代码主要提供了一个位移操作的软件实现 是类SPI的操作
而真正的SPI通信是由硬件实现的 有固定的引脚 有片选 能够全双工通信

评论区