74hc595 shift register를 이용한 아두이노 포트 확장


여러개의 LED를 켜려면 아두이노의 핀을 여러개를 사용해야한다.
그러나 핀 1개로 여러개의 LED또는 FND, 도트매트릭스등을 다룰수 있다.
즉 74hc595 shift register를 활용하여 아두이노의 포트를 확장하는 것이다.

74hc595는 8-bit serial-in, serial or parallel-out shift register 로
8비트의 데이터를 받아 병렬로 출력해주는 IC로
아두이노핀에서 10101010을 보내면
데이터를 받아 Q0핀~Q7핀에서 동시에 10101010을 각각 출력한다.
즉 Q0 -> 1
    Q1 -> 0
    Q2 -> 1
    Q3 -> 0
    Q4 -> 1
    Q5 -> 0
    Q6 -> 1
    Q7 -> 0을 출력해준다.(핀은 아래그림 참조)
Q7'핀은 8bit이상의 데이터를 보낼때 다음의 74hc595로 데이터를 넘긴다.

각 핀연결은
PINS 1-7, 15  Output Pins (병렬출력)
 PIN 8  GND
 PIN 9  Serial Out(다음IC로 데이터를 넘김)
 PIN 10  Master Reclear, active low (+연결한다)
 PIN 11  Shift register clock pin (아두이노와 연결)
 PIN 12  Storage register clock pin (latch pin) (아두이노와 연결)
 PIN 13  Output enable, active low (GND연결한다)
 PIN 14  Serial data input (아두이노와 연결)
 PIN 16  Positive supply voltage (Vcc)

74hc595의 동작은 클럭핀, 래치핀, 데이터핀으로 동작을 시킨다.
데이터핀에 데이터를 주고 클럭을 주고 래치핀에 신호를 주면 데이터가 74hc595의 각핀에서
데이터가 병렬로 출력된다.
(이부분이 난해하다. 74hc595의 전기적인 동작을 이해하지 못해 그냥 그렇다고 받아들일뿐 TT)

작동원리야 그렇지만
아두이노에서 간단하게 74hc595를 사용할 수 있도록 shiftOut()함수를 제공한다.
shiftOut(datapin, clockpin, MSBFIRST/LSBFIRST,value);로
datapin은 74hc595의 datapin과 연결된 아두이노 핀번호
clockpin은 74hc595의 clockpin과 연결된 아두이노 핀번호
MSBFIRST 전송할 데이터를 상위비트부터 보냄  LSBFIRST전송할 데이터를 하위비트부터 보냄
value에 보낼 값을 써주면 된다.


자 FND를 켜보자
사용된 FND는 애노드형이다.


소스 스케치
----------------------------------------------------------------------------
/* 74HC595 쉬프트 레지스터를 이용하여 FND에 숫자 표시하기*/
int clock = 2;  //74HC595의 클럭핀과 연결
int latch = 3;  //74HC595의 래치핀과 연결
int data = 4;  //74HC595의 데이터핀과 연결
int val[10] =
{0b10000001,0b11110011,0b01001001,0b01100001,0b00110011,0b00100101,0b00000101,0b11110001,
0b00000001,0b00110001};     //FND에 표시될 숫자로 0~9다
void setup(){
  pinMode(clock, OUTPUT);
  pinMode(latch, OUTPUT);
  pinMode(data, OUTPUT);
}
void loop(){
  for(int i = 0; i<10; i++){
    LEDs(val[i]);
    delay(500);
  }
}
void LEDs(int a){
  digitalWrite(latch, LOW);   //래치를 내리고
  shiftOut(data,clock,MSBFIRST, a);  //데이터를 보내고
  digitalWrite(latch, HIGH);   //래치를 올린다. 74HC595에서 데이터를 FND로 출력함.
}
------------------------------------------------------------------------------ 

작동영상


서보모터 제어


서보모터는 일정한 각도내에서만 회전을 하는 모터로 
RC비행기의 타각조절이나 휴머노이드 로봇등에서 많이 사용한다.

서보의 작동은 일정 시간 동안 신호를 보내면 그신호 펄스 폭이
서보의 작동 각도가 된다.




그림에 의하면 1.5ms동안 펄스를 보내면 서보는 90도 위치로 회전
다시 1ms동안 펄스를 보내면 서보는 0도에 위치한다.
즉 서보는 매20ms마다 신호를 받으려 기다리고
그때마다 보내는 신호의 길이에 따라 해당 각도로 회전한다.

소스 스케치
이 소스는 서보를 제어하기 위해 신호를 직접 계산함
--------------------------------------------------------------------------- 
// 키보드의 < , > ,스페이스키 서보를 제어.
// 날짜 : Created 10 December 2007
// 저자 : Brian D. Wendt  http://principialabs.com/
// 참조 : Tom Igoe의 코드를 적용함 : http://itp.nyu.edu/physcomp/Labs/Servo

int servoPin     =  2;    // 서보에 신호를 주기위한 핀
int minPulse     =  600;  // 서보에 최소신호폭 0.6ms로 계산됨
int maxPulse     =  2400; // 최대 신호폭 2.4ms로 계산됨
int turnRate     =  100;  // 키보드 조작으로 서보를 조절할때 움직이는 폭 0.1ms 
int refreshTime  =  20;   // 서보가 새신호를 받아오는 시간 간격 
  
int centerServo;         // 서보의 중앙위치 값을 저장하기 위한 변수
int pulseWidth;          // 서보의 신호폭 
int moveServo;          // raw user input 
long lastPulse   = 0;   // recorded time (ms) of the last pulse
 
void setup()  

  pinMode(servoPin, OUTPUT);  // Set servo pin as an output pin 
  centerServo = maxPulse - ((maxPulse - minPulse)/2); 
  Serial.begin(9600); // 키보드로 제어하기 위해 통신 시작
  pulseWidth = centerServo;   // 처음 켤때 서보의 위치를 중앙으로 주기위함. 
  } 
  
void loop()                   

   // 입력을 기다린다
   if (Serial.available() > 0)
  { 
    // 입력된 값을 읽는다
    moveServo = Serial.read(); 
  
    // 키보드 문자값에서, ASCII '<' 는 44, ASCII '>'는 46 , 스페이스는 32
    if (moveServo == 44) { pulseWidth = pulseWidth - turnRate; } 
    if (moveServo == 46) { pulseWidth = pulseWidth + turnRate; } 
    if (moveServo == 32) { pulseWidth = centerServo; } 
  
    // min 과 max에서 서보를 정지한다.
    if (pulseWidth > maxPulse) { pulseWidth = maxPulse; } 
    if (pulseWidth < minPulse) { pulseWidth = minPulse; } 
  } 
  
  // 서보의 펄스는 pulseWidth으로 매 20 ms 마다 갱신된다.
  // 만일 각도가 그대로 이면, 서보의 위치를 고정한다.
  if (millis() - lastPulse >= refreshTime)
 { 
    digitalWrite(servoPin, HIGH);   // 신호를 보내기 시작
    delayMicroseconds(pulseWidth);  // 신호의 간격
    digitalWrite(servoPin, LOW);    // 신호를 멈춤 
    lastPulse = millis();           // save the time of the last pulse 
  } 
}

위 소스는 어렵고 길다.
작동 원리를 알아보기 위해 작성된것이고
아두이노가 제공하는 서보 함수를 이용하면 매우 간단하다.

/*센서로 서보 제어*/
#include <Servo.h>    //서보를 사용하기 위한 해더 파일
int sensorPin = A0;   //센서핀 설정
int val = 0;   // 센서값을 저장하기 위한 변수
Servo servoA;  //서보사용을 위한 servoA 선언
void setup(){
  servoA.attach(9);  // 서보연결핀은 9
}
void loop(){
  val = analogRead(sensorPin);  // 센서에서 값을 읽어 val에 저장
  val = map(val,0,1023,0,179);   //  map함수 측정된 0~1023사이의 val 값을 0~179 값으로 변환
  servoA.write(val);    // 서보에 변환된 val값을 씀. 그 값(각도위치)에 따라 서보 작동
}
------------------------------------------------------------------------------------

작동영상





피에조 스피커를 이용, 소리에 반응하는 LED


피에조 센서를 이용하여 외부에서 자극을 주면 LED가 반응하도록
하였다.

피에조 센서는 외부 소리나 압력에 의해 진동이 발생하면 전류가 흐른다.
피에조 센서를 이용해야하나 구조는 같으므로 피에조 스피커(부저)를 센서로 이용 
LED를 소리에 반응 하도록 하였다.

일단 아두이노에 피에조 스피커를 연결은


회로도 상으로는 1메가옴의 저항을 연결했지만 저항이 없어 10킬로옴으로 대체

소스 스케치
/*피에조 스피커를 이용 소리에 반응하는 LED*/
int ledPin = 10;
int sensorPin = A0;
int ledstate = LOW;
int val = 0;
int sensorcut = 3; //최저 소리감지값
void setup(){
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}
void loop(){
  val = analogRead(sensorPin);

  if(val  > sensorcut){
    ledstate = !ledstate;
    digitalWrite(ledPin,ledstate);
    Serial.println("knock!");
    Serial.println(val);
    delay(100);
 }
}

위 소스 스케치에서 if문을 while문으로 대치하면
void loop(){
  val = analogRead(sensorPin);
  while(val  <= sensorcut); // val 값을 미리 읽고 while에 쓰면 작동하지 않음
  while((val = analogRead(sensorPin)) <= sensorcut);// while문 안에 조건을 넣으면 작동
  ledstate = !ledstate;
  digitalWrite(ledPin,ledstate);
  Serial.println("knock!");
  Serial.println(val);
  delay(100);
}
도 가능하다.





작동영상 

+ Recent posts