타이머 인터럽트로 작업하는 방법을 배우십시오. 병렬 프로세스가 있는 간단한 프로그램을 작성해 보겠습니다.

실제 프로그램에서는 많은 작업을 동시에 수행해야 합니다. 서론에서 예를 들었습니다. 그녀가 하는 일은 다음과 같습니다.

작업

주기 시간
3개의 버튼을 확인하고, 이들의 신호를 처리하여 잡담을 제거합니다. 2ms
7세그먼트 LED 데이터 재생성 2ms
2개의 온도 센서 DS18B20에 대한 제어 신호를 생성하고 이들로부터 데이터를 읽습니다. 센서에는 1-와이어 직렬 인터페이스가 있습니다. 각 비트에 대해 100μs,
1초 총 읽기 주기
펠티에 소자, 공급 전압의 전류 및 전압 아날로그 값 읽기 100μs
아날로그 전류 및 전압 값의 디지털 필터링 10ms
펠티에 소자의 전력 계산 10ms
PID(비례 적분 차동) 전류 및 전압 안정화 컨트롤러 100μs
전원 조절기 10ms
온도 조절기 1 초
보호 기능, 데이터 무결성 제어 1 초
관리, 시스템의 일반 논리 10ms

이러한 모든 작업은 주기적으로 수행되며 모두 주기가 다릅니다. 그들 중 누구도 멈출 수 없습니다. 작동 기간의 시간이 단기적으로라도 변경되면 심각한 측정 오류, 안정 장치의 잘못된 작동, ​​표시등의 깜박임, 버튼 누름에 대한 불안정한 응답 등 문제가 발생할 수 있습니다.

냉장고 컨트롤러 프로그램에는 이러한 모든 작업을 수행하는 여러 병렬 프로세스가 있습니다. 병렬 프로세스는 작업이 동시에 실행되는 프로세스입니다.

이전 단원에서 버튼 개체에 대한 클래스를 만들었습니다. 우리는 이것이 병렬 처리에서 신호를 처리하기 위한 클래스라고 말했습니다. 정상적인 작동을 위해서는 규칙적인 주기로 신호 처리 기능(메소드)을 호출해야 합니다(우리는 2ms의 시간을 선택했습니다). 그런 다음 버튼 또는 신호의 현재 상태를 나타내는 기호는 프로그램의 어디에서나 사용할 수 있습니다.

하나의 루프에 버튼의 상태를 처리하고 LED를 제어하는 ​​코드를 배치했습니다. 그리고 루프의 끝에 delay(2) 함수를 넣습니다. 그러나 루프에서 프로그램을 실행하는 데 걸리는 시간은 전체 루프 시간을 변경합니다. 그리고 사이클 주기는 분명히 2ms와 같지 않습니다. 또한 delay() 함수를 실행하는 동안 프로그램이 정지되어 다른 작업을 수행할 수 없습니다. 복잡한 프로그램은 완전한 혼란을 초래할 것입니다.

종료 - 하드웨어 타이머에서 중단 시 버튼의 상태를 처리하는 기능을 호출합니다. 2ms마다 프로그램의 메인 루프가 중단되어야 하고 버튼 신호가 처리되고 컨트롤은 중단된 코드로 메인 루프로 돌아갑니다. 버튼 신호의 짧은 처리 시간은 메인 루프의 실행에 큰 영향을 미치지 않습니다. 저것들. 버튼 처리는 메인 프로그램에 대해 감지할 수 없을 정도로 병렬로 발생합니다.

타이머에서 하드웨어 인터럽트.

하드웨어 인터럽트는 일종의 이벤트를 보고하는 신호입니다. 도착하면 프로그램 실행이 일시 중단되고 제어가 인터럽트 처리기로 넘어갑니다. 처리 후 제어는 중단된 프로그램 코드로 돌아갑니다.

프로그램의 관점에서 인터럽트는 프로그램 코드와 직접 관련이 없는 외부 이벤트에 대한 함수 호출입니다.

타이머의 인터럽트 신호는 주어진 주기로 주기적으로 생성됩니다. 특정 값에 도달하면 코드를 재설정하는 논리가 있는 카운터인 하드웨어 타이머를 형성합니다. 리셋 로직에 대한 코드를 프로그래밍 방식으로 설정하여 타이머 인터럽트 기간을 설정할 수 있습니다.

Arduino 타이머 기간의 모드와 시간 설정은 마이크로 컨트롤러의 하드웨어 레지스터를 통해 수행됩니다. 원하는 경우 수행 방법을 알아낼 수 있습니다. 그러나 MsTimer2 라이브러리를 사용하는 더 간단한 옵션을 제안합니다. 또한 타이머 모드를 설정하는 경우는 드물기 때문에 라이브러리 기능을 사용해도 프로그램 속도가 느려지지 않습니다.

라이브러리 MsTimer2.

라이브러리는 마이크로컨트롤러의 타이머 2에서 하드웨어 인터럽트를 구성하기 위한 것입니다. 다음 세 가지 기능만 있습니다.

  • MsTimer2::set(부호 없는 긴 ms, 무효(*f)())

이 기능은 인터럽트 기간을 ms 단위로 설정합니다. 이 기간 동안 인터럽트 핸들러 f가 호출됩니다. void(아무것도 반환하지 않음)로 선언되어야 하며 인수를 사용하지 않아야 합니다. * f는 함수 포인터입니다. 대신 함수의 이름을 쓰십시오.

  • MsTimer2::시작()

이 기능은 타이머 인터럽트를 활성화합니다.

  • MsTimer2::stop()

이 기능은 타이머 인터럽트를 비활성화합니다.

함수 이름 앞에 MsTimer2::를 써야 합니다. 라이브러리는 namespace 지시문을 사용하여 작성됩니다.

라이브러리를 설치하려면 MsTimer2 디렉터리를 Arduino IDE의 작업 폴더에 있는 라이브러리 폴더에 복사합니다. 그런 다음 Arduino IDE 프로그램을 실행하고 스케치 -> 라이브러리 포함 MsTimer2 라이브러리가 라이브러리 목록에 있는지 확인합니다.

zip 아카이브에서 MsTimer2 라이브러리를 다운로드할 수 있습니다. 설치하려면 압축을 풀어야 합니다.

버튼 신호를 병렬 처리하는 간단한 프로그램입니다.

이제 6단원의 버튼 하나와 LED가 있는 간단한 프로그램을 작성해 보겠습니다. 하나의 버튼은 구성표에 따라 Arduino 보드에 연결됩니다.

다음과 같습니다.

버튼을 누를 때마다 Arduino 보드의 LED가 상태를 변경합니다. MsTimer2 및 Button 라이브러리를 설치해야 합니다.

MsTimer2

그리고 지불합니다. 단 40 루블. 사이트의 모든 리소스에 대한 액세스를 위해 매월!

// 10과의 스케치_10_1
// 버튼을 누르면 LED 상태가 변경됩니다.

#포함
#포함

#define LED_1_PIN 13 //
#define BUTTON_1_PIN 12 // 핀 12에 연결된 버튼

버튼 버튼1(BUTTON_1_PIN, 15); // 객체 생성 - 버튼

무효 설정()(

MsTimer2::set(2, timerInterupt); // 타이머 인터럽트 기간을 2ms로 설정
MsTimer2::start(); //
}

무효 루프() (

// LED 제어
if (button1.flagClick == true) (
// 버튼 클릭이 있었다



}
}

// 인터럽트 핸들러
무효 timerInterupt() (
버튼1.scanState(); // 버튼에 대한 안정 상태 대기 메소드 호출
}

setup() 함수에서 타이머 인터럽트 주기 시간을 2ms로 설정하고 인터럽트 핸들러 timerInterrupt의 이름을 지정합니다. 버튼 신호 처리 함수 button1.scanState()는 2ms마다 타이머 인터럽트 핸들러에서 호출됩니다.

따라서 병렬 프로세스에서 버튼의 상태를 처리합니다. 그리고 프로그램의 메인 루프에서 버튼 클릭의 신호를 확인하고 LED의 상태를 변경합니다.

휘발성 한정자.

이전 프로그램에서 loop() 루프를 변경해 보겠습니다.

무효 루프() (

동안(참) (
if (button1.flagClick == true) 중단;
}

// 버튼 클릭이 있었다
button1.flagClick=거짓; // 리셋 기능
digitalWrite(LED_1_PIN, !디지털읽기(LED_1_PIN)); // LED 반전
}

논리적으로 아무것도 변경되지 않았습니다.

  • 첫 번째 버전에서 프로그램은 루프 루프를 끝까지 거쳐 그 안에 있는 button1.flagClick 플래그를 분석했습니다.
  • 두 번째 변형에서 프로그램은 무한 while 루프에서 button1.flagClick 플래그를 구문 분석합니다. 플래그가 활성화되면 while 루프에서 벗어나 LED 상태를 반전시킵니다.

유일한 차이점은 프로그램이 루프에서 또는 while에서 회전하는 루프입니다.

그러나 마지막 버전의 프로그램을 실행하면 LED가 버튼을 눌러도 응답하지 않는 것을 볼 수 있습니다. 클래스를 제거하고 프로그램을 단순화합시다.

#포함
#define LED_1_PIN 13 // 핀 13에 연결된 LED
정수 수 = 0;

무효 설정()(
핀모드(LED_1_PIN, 출력); // LED의 출력을 출력으로 정의
MsTimer2::set(500, timerInterupt); // 타이머 인터럽트 기간을 500ms로 설정
MsTimer2::start(); // 타이머 인터럽트 활성화
}

무효 루프() (

동안 (사실)(
if (count != 0) break;
}

카운트=0;
digitalWrite(LED_1_PIN, !디지털읽기(LED_1_PIN)); // LED 상태 반전
}

// 인터럽트 핸들러
무효 timerInterupt() (
카운트++;
}

이 프로그램에서 카운터는 500ms마다 인터럽트 처리기에서 1씩 증가합니다. while 루프에서 분석되며 break에 의해 루프를 종료하고 LED의 상태를 반전시킵니다. 더 간단한 프로그램은 상상할 수 없지만 작동하지도 않습니다.

사실 C ++ 언어의 컴파일러는 지능의 범위까지 프로그램을 최적화합니다. 때로는 작동하지 않습니다. 컴파일러는 while 루프의 count 변수에 대해 수행된 작업이 없음을 확인합니다. 따라서 그는 카운트 상태를 한 번만 확인하면 충분하다고 생각합니다. 주기에서 확인해야 할 사항, 절대 변경할 수 없는 사항. 컴파일러는 코드를 수정하여 실행 시간에 최적화합니다. 간단히 말해서 루프에서 변수 검사 코드를 제거합니다. 컴파일러는 카운트 변수가 인터럽트 핸들러에서 상태를 변경한다는 것을 이해할 수 없습니다. 결과적으로 우리는 while 루프에 갇혀 있습니다.

루프 루프를 끝까지 실행하는 프로그램 버전에서 컴파일러는 모든 변수가 변경될 수 있다고 간주하고 확인 코드를 남깁니다. 시스템 함수에 대한 호출을 while 루프에 삽입하면 컴파일러도 변수가 변경될 수 있다고 결정합니다.

예를 들어, while 루프에 delay() 함수에 대한 호출을 추가하면 프로그램이 작동합니다.

동안 (사실)(
if (count != 0) break;
지연(1);
}

루프가 끝까지 실행되고 프로그램이 어디에도 걸리지 않는 프로그램을 개발하는 것은 좋은 스타일입니다. 다음 강의는 무한 while 루프에서 플래그를 구문 분석하는 유일한 코드가 될 것입니다. 또한 모든 프로그램에서 루프를 끝까지 실행할 계획입니다.

때로는 이것이 쉽지 않거나 효과적이지 않습니다. 그런 다음 volatile 한정자를 사용해야 합니다. 변수를 선언할 때 지정되며 컴파일러에 사용을 최적화하지 않도록 지시합니다. 변수가 병렬 프로세스와 같은 다른 프로그램 블록에서 변경될 수 있으므로 컴파일러가 변수 값에 대해 가정하지 못하도록 합니다. 또한 컴파일러는 범용 레지스터가 아닌 RAM에 변수를 할당합니다.

count를 선언할 때 프로그램에 작성하는 것으로 충분합니다.

휘발성 정수 수 = 0;

모든 옵션이 작동합니다.

버튼 제어 프로그램의 경우 Button 클래스 인스턴스의 속성이 변경될 수 있음을 선언해야 합니다.

휘발성 버튼 버튼1(BUTTON_1_PIN, 15); // 객체 생성 - 버튼

내 관찰에 따르면 volatile 한정자를 사용해도 프로그램 코드의 길이가 늘어나지 않습니다.

Bounce 라이브러리와 버튼 신호 처리 방법 비교.

바운스 버튼을 디바운싱하기 위한 기성 라이브러리가 있습니다. 버튼의 상태를 확인하는 것은 update() 함수가 호출될 때 발생합니다. 이 함수에서:

  • 버튼 신호를 읽습니다.
  • update()에 대한 이전 호출 동안의 상태와 비교;
  • millis() 함수를 사용하여 이전 호출 이후 얼마나 많은 시간이 경과했는지 확인합니다.
  • 버튼의 상태가 변경되었는지 여부가 결정됩니다.
  • 그러나 이것은 병렬 신호 처리가 아닙니다. update() 함수는 일반적으로 기본 비동기 프로그램 루프에서 호출됩니다. 일정 시간 이상 호출되지 않으면 버튼 신호 정보가 손실됩니다. 불규칙한 호출은 알고리즘의 잘못된 작동으로 이어집니다.
  • 함수 자체에는 상당히 큰 코드가 있으며 Button() 라이브러리의 함수보다 훨씬 오래 실행됩니다.
  • 평균값에 의한 신호의 디지털 필터링은 전혀 존재하지 않습니다.

복잡한 프로그램에서는 이 라이브러리를 사용하지 않는 것이 좋습니다.

다음 수업에서는 병렬 프로세스를 사용하여 더 복잡한 프로그램을 작성합니다. 하나의 타이머 인터럽트에서 서로 다른 시간 간격으로 프로그램 블록을 실행하는 방법을 배웁니다.

범주: . 북마크를 할 수 있습니다.

이 기사에서는 SPI 버스에 대한 여러 슬레이브 장치의 병렬 및 직렬 연결, 시프트 레지스터의 직렬 연결, 이중 7-세그먼트 디스플레이 작업, Arduino의 독립 프로세스 구현 문제를 다룹니다. 결과적으로, 우리는 뱀이 이중 7-세그먼트를 따라 달리고 이 시간에 다른 단일 세그먼트에서 초가 똑딱거리는 회로를 만들 것입니다.

우리는 SPI 버스에 대해 알게 되었고 슬레이브를 마스터에 연결하려면 4개의 와이어가 필요하다는 것을 배웠습니다. 그러나 슬레이브 장치가 두 개 이상인 경우 이미 흥미로운 옵션이 있습니다.

SPI 버스에 병렬로 장치 연결

병렬로 연결하면 여러 슬레이브 장치가 공통 와이어를 사용합니다. SCLK, 모시그리고 미소, 각 슬레이브에는 자체 라인이 있습니다. 봄 여름 시즌 . 퍼실리테이터가 결정 교환할 장치, 에 의해 낮은 신호를 형성 봄 여름 시즌 .
연결하기 위함임을 알 수 있다. N필요한 장치 N윤곽 봄 여름 시즌 , 즉, SPI 환경의 기능을 위해 N이를 위해 슬레이브를 할당해야 합니다. n+3마이크로 컨트롤러의 다리.

SPI 버스에 장치의 직렬 연결

장치가 직렬로 연결되면 공통 와이어를 사용합니다. SCLK그리고 봄 여름 시즌 , 그리고 하나의 출력은 다른 하나의 입력에 연결됩니다. 모시마스터가 첫 번째 장치에 연결하고 미소- 마지막으로. 즉, SPI 버스의 마스터의 경우 이것은 하나의 장치입니다.
이러한 연결을 통해 예를 들어 두 개의 8비트 시프트 레지스터에서 하나의 16비트 시프트 레지스터를 만들 수 있습니다.
이러한 연결의 매력에 주목해야 합니다. 최소 3개, 최소 8개 장치를 연결하면 컨트롤러에서 4개의 다리만 필요합니다.

두 시프트 레지스터의 직렬 연결
74HC595 시프트 레지스터를 다시 살펴보겠습니다.

우리는 그것을 기억합니다 디에스- 직렬 입력 핀이 있고, Q0-Q7직렬 출력 핀. Q7S, 회로에 레지스터가 하나만 있을 때 사용하지 않은 레지스터의 직렬 출력입니다. 레지스터에 1바이트 이상을 전송할 때 사용합니다. 이 핀을 통해 후속 레지스터에 대한 모든 바이트가 순차적으로 푸시되고 마지막으로 전송된 바이트는 첫 번째 레지스터에 남게 됩니다.


첫 번째 레지스터의 Q7S 핀을 두 번째 레지스터의 DS 핀(필요한 경우 등등)에 연결하여 이중(삼중 등) 레지스터를 얻습니다.

듀얼 7세그먼트 디스플레이 연결하기

이중 7-세그먼트 디스플레이는 일반적으로 각 문자에 대해 9개, 18개 다리가 있는 장치입니다. 다이어그램을 살펴보겠습니다(내 디스플레이에는 LIN-5622SR이라는 레이블이 지정되어 있으며 배선 다이어그램이 고유할 가능성이 높음).

이것은 일반적인 양극 디스플레이입니다. 즉, com1과 com2 모두 다이오드를 켜기 위해 높은 TTL 레벨과 해당 다리의 낮은 레벨이 필요합니다. 공통 음극 디스플레이가 있는 경우 반대 작업을 수행하십시오!

다이어그램에 표시된 대로 디스플레이를 연결합니다.

왼쪽 디스플레이는 첫 번째 레지스터에 연결됩니다. 1A는 Q0 레그, 1B는 Q1 레그, 1C는 Q2 레그 등입니다. 공통 접점 com1을 접지에 연결합니다. 오른쪽 디스플레이에서도 동일한 작업을 수행합니다. 2A는 Q0 레그, 2B는 Q1 레그 등으로, 공통 접점 com2는 지면에 연결됩니다.

회로는 그림과 같이 보이지 않을 것입니다. 디스플레이의 핀 배치가 제 것과 다르면 여기에서 연결할 때 주의해야 합니다. 디스플레이에 공통 음극이 있는 경우 com1 및 com2가 전원에 연결됩니다!

듀얼 7-세그먼트 디스플레이의 단순한 뱀

그래서 지난 시간에 단일 문자 디스플레이에서 숫자를 밝히는 방법을 배웠고 오늘은 두 문자 디스플레이에 뱀을 그릴 것입니다. 우선, 세 개의 세그먼트로 구성되고 원을 그리는 간단한 뱀을 만들 것입니다.

우리의 주기는 8개의 프레임으로 구성되며 각 프레임은 특정 3개의 LED를 켭니다. 첫 번째 프레임에서 1E, 1F, 1A가 켜집니다(다이어그램 참조), 두 번째 - 1F, 1A, 2A, 세 번째 - 1A, 2A, 2B 등, 여덟 번째 - 1D, 1E, 1F .

다시 말하지만, 편의를 위해 기본적으로 비트가 가장 높은 것부터 전송된다는 점을 기억하면서 바이트 테이블을 만들어 보겠습니다. 2시간.

액자

1 abcd efgh

2 abcd 에프그

마녀

0111 0011

1111 1111

ECFF

0111 1011

0111 1111

ED EF

0111 1111

0011 1111

EF CF

1111 1111

0001 1111

FF 8F

1111 1111

1000 1111

FF 1F

1110 1111

1100 1111

7F 3F

1110 0111

1110 1111

7E 7F

1110 0011

1111 1111

7CFF


호스트는 와이어에서 낮은(활성) 레벨을 설정해야 합니다. 봄 여름 시즌 , 2바이트를 전송하고 와이어를 해제합니다. 이 순간 래치가 발생하고 각 레지스터에 바이트가 기록되고 두 문자가 켜집니다.

#포함<SPI .h> // SPI 라이브러리 연결
열거형(reg=9); //라인 선택봄 여름 시즌 Arduino의 9 번째 핀에 등록하십시오.

무효의 설정 () {
SPI.begin(); //SPI 초기화
//전송을 위해 선택된 핀을 출력 모드로 변환
핀모드(reg, OUTPUT);
}


무효의 고리 () {
//우리가 보낼 바이트로 배열을 채웁니다.
정적 uint8_t 자리 =
(0xFF,0xCE,0xFF,0xDE,0xFC,0xFE,0xF8,0xFF,
0xF1,0xFF,0xF3,0xF7,0xF7,0xE7,0xFF,0xC7};
//배열에서 2바이트를 전송하고 레지스터를 래치합니다.
for (int i=0;i<16;i+=2){
디지털 쓰기(reg, LOW);
SPI .transfer(숫자[i]);
SPI.전송(숫자);
digitalWrite(reg, HIGH);
지연(80); // 프레임 사이에 일시 중지
}
}


프로그램 비디오:

Arduino의 병렬 프로세스

Arduino 개발자가 지연 없는 Blink 예제에 특별한 관심을 기울이는 이유는 무엇입니까?

일반적으로 Arduino 프로그램은 선형입니다. 먼저 한 가지 작업을 수행한 다음 다른 작업을 수행합니다. 위의 예에서 우리는 함수를 사용했습니다. 지연(80)각 프레임이 이전 프레임보다 80밀리초 뒤에 그려지도록 합니다. 그러나 결국 이 80밀리초 동안 프로세서는 아무 것도 하지 않으며 아무 것도 하도록 허용하지 않습니다! 둘 이상의 병렬 프로세스를 실행하려면 프로그램을 구축하는 개념을 변경해야 합니다. 지연() .

새로운 디자인의 핵심은 타이머가 될 것입니다. 타이머는 시간을 계산하고 우리는 이 또는 그 이벤트가 특정 간격으로 발생하도록 강제할 것입니다. 예를 들어 시계 디스플레이는 1초마다 똑딱거리고 LED는 0.86초마다 깜박입니다.

아두이노에는 프로그램 시작부터 시간을 세는 것이 있는데 이것을 밀리(). 그것의 도움으로 작업의 "병렬화"가 구성됩니다.

최종 프로젝트: 시계와 교활한 뱀


이 다이어그램을 조합해 보겠습니다.

왼쪽 및 중간 레지스터는 리더의 관점에서 하나의 장치로, 오른쪽 레지스터는 다른 장치로 작동합니다. 이 두 장치가 동일한 와이어를 사용하는 것을 볼 수 있습니다. SCLK(Arduino 핀 13, 주황색으로 표시된 와이어) 및 모시(11번 핀, 노란색), 봄 여름 시즌 다른 것들이 사용됩니다(핀 8과 9, 녹색). 7-세그먼트 디스플레이를 레지스터에 연결하는 것은 내 특정 모델에 대해 표시되며 아마도 귀하의 모델과 일치하지 않을 것입니다.


이번에는 뱀을 더 교활하게 만들 것입니다. 늑대가 "잠깐만요!" 시리즈의 교차로를 따라 오토바이를 탔던 것과 같은 방식으로 모든 세그먼트를 통과할 것입니다. 차고에서 같은 오토바이를 타고 헬멧을 씁니다.

이 스네이크의 바이트 시퀀스는 다음과 같습니다.

정적 uint8_t 스네이크 =


이제 요점:기능 밀리()앉아서 시작 부분부터 밀리초를 계산합니다. 각 루프의 시작 부분에서 값을 기억합니다. 밀리()변수로 시간제 노동자.변수 설정 뱀타이머Prev그리고 digitTimerPrev, 이전 이벤트의 순간을 저장합니다. 뱀타이머Prev뱀 애니메이션의 이전 프레임이 포함되어 있습니다. digitTimerPrev- 이전 숫자 포함. 현재 시차( 시간제 노동자) 및 이전( 뱀타이머Prev또는 digitTimerPrev)가 지정된 기간(이 경우 각각 80ms 및 1000ms)이 되면 다음 프레임/바이트를 전송합니다.

이런 식으로,

  • 컨트롤러는 80ms마다 라인의 신호를 낮춥니다. 봄 여름 시즌듀얼 디스플레이, 2바이트를 전송하고 라인을 해제합니다.
  • 매초마다 컨트롤러는 라인의 신호를 낮춥니다. 봄 여름 시즌단일 디스플레이, 1바이트를 전송하고 라인을 해제합니다.
아두이노에서 구현해보자. 나는 이미 모든 것을 자세히 설명했습니다. 나는 논평의 의미가 없다고 생각합니다.

#포함<SPI .h>

열거형(snakePin = 9, digitPin = 8);
서명되지 않은 긴 타이머=0, snakeTimerPrev=0, digitTimerPrev=0;
정수 i=0, j=0;



무효의 설정 () {
SPI.begin();
핀모드(숫자핀, 출력);
핀모드(뱀핀, 출력);
}


무효의 고리 () {
정적 uint8_t 자리 =
(0xC0.0xF9.0xA4.0xB0.0x99.0x92.0x82.0xF8,
0x80.0x90.0x88.0x83.0xC6.0xA1.0x86.0x8E);
정적 uint8_t 뱀 =
(0xFF,0x9E,0xFF,0xDC,0xFF,0xF8,0xFF,0xF1,
0xFF,0xE3,0xFF,0xA7,0xBF,0xAF,0xBD,0xBF,
0xBC, 0xFF, 0xDC, 0xFF, 0xCE, 0xFF, 0xC7, 0xFF,
0xE3,0xFF,0xB3,0xFF,0xBB,0xBF,0xBF,0x9F);


타이머=밀리();


if (timer-snakeTimerPrev>80)(
digitalWrite(snakePin, LOW);
SPI.transfer(뱀[j]);
SPI.transfer(뱀);
digitalWrite(snakePin, HIGH);
제이<30 ? j+=2: j=0;
SnakeTimerPrev=타이머;
}
if (timer-digitTimerPrev>1000)(
digitalWrite(digitPin, LOW);
SPI.transfer(숫자[i]);

이 프로그램을 설치하면 Arduino IDE와 얼마나 유사한지 놀라게 될 것입니다. 놀라지 마십시오. 두 프로그램은 동일한 엔진에서 만들어집니다.

응용 프로그램에는 라이브러리를 포함하여 많은 기능이 있습니다. 연속물, 그래서 우리는 보드와 보드 사이의 데이터 전송을 연결할 수 있습니다.

Arduino IDE를 시작하고 데이터 출력의 가장 간단한 예를 선택하여 직렬 포트:

void setup() ( Serial.begin(9600); ) void loop() ( Serial.println("Hello Kitty!"); // 다시 보내기 전에 500밀리초를 기다립니다. delay(500); )

예제를 실행하고 코드가 작동하는지 확인합시다.

데이터 가져오기

이제 우리는 동일한 텍스트를 . 새 프로젝트를 시작하고 코드를 작성합니다.

첫 번째 단계는 라이브러리를 가져오는 것입니다. 가자 스케치 | 라이브러리 가져오기 | 연속물. 스케치에 선이 나타납니다.

가져오기 처리.serial.*; 시리얼 시리얼; // 직렬 포트 객체 생성 String 수신됨; // 직렬 포트에서 받은 데이터 void setup() ( String port = Serial.list(); serial = new Serial(this, port, 9600); ) void draw() ( if (serial.available() > 0) ( // 데이터가 있으면 수신 = serial.readStringUntil("\n"); // 데이터 읽기 ) println(received); // 데이터를 콘솔에 표시 )

직렬 포트에서 데이터를 수신하려면 클래스의 개체가 필요합니다. 연속물. Arduino에서 문자열 데이터를 보내므로 Processing에서도 문자열을 가져와야 합니다.

방법에서 설정()사용 가능한 직렬 포트를 가져와야 합니다. 일반적으로 이것은 목록에서 사용 가능한 첫 번째 포트입니다. 그 후에 우리는 객체를 설정할 수 있습니다 연속물, 포트 및 데이터 전송 속도를 나타냅니다(속도가 일치하는 것이 바람직함).

보드를 다시 연결하고 Processing에서 스케치를 실행하고 애플리케이션 콘솔에서 들어오는 데이터를 관찰해야 합니다.

처리를 통해 콘솔로 작업할 수 있을 뿐만 아니라 표준 창을 만들 수도 있습니다. 코드를 다시 작성해 보겠습니다.

가져오기 처리.serial.*; 시리얼 시리얼; // 직렬 포트 객체 생성 String 수신됨; // 직렬 포트에서 받은 데이터 void setup() ( size(320, 120); String port = Serial.list(); serial = new Serial(this, port, 9600); ) void draw() ( if (serial .available() > 0) ( // 데이터가 있으면 읽어서 변수에 쓰기 receive = serial.readStringUntil("\n"); ) // 텍스트 설정 textSize(24); clear (); if (received != null) ( text(received, 10, 30); ) )

예제를 다시 실행하고 한 곳에서 다시 그려지는 비문이 있는 창을 보겠습니다.

그래서 우리는 Arduino에서 데이터를 받는 방법을 배웠습니다. 이를 통해 아름다운 그래프를 그리거나 센서 판독값을 모니터링하는 프로그램을 만들 수 있습니다.

데이터 전송

우리는 보드에서 데이터를 수신할 수 있을 뿐만 아니라 보드로 데이터를 보내어 컴퓨터에서 명령을 실행하도록 강요합니다.

Processing에서 문자 "1"을 보낸다고 가정해 보겠습니다. 보드가 보낸 문자를 감지하면 포트 13(내장)의 LED를 켭니다.

스케치는 이전 스케치와 유사합니다. 예를 들어 작은 창을 만들어 보겠습니다. 창 영역을 클릭하면 "1"을 보내고 확인을 위해 콘솔에 복제합니다. 클릭이 없으면 "0" 명령이 전송됩니다.

가져오기 처리.serial.*; 시리얼 시리얼; // 직렬 포트 객체 생성 String 수신됨; // 직렬 포트에서 받은 데이터 void setup() ( size(320, 120); String port = Serial.list(); serial = new Serial(this, port, 9600); ) void draw() ( if (mousePressed == true) ( ​​​​//창 내에서 클릭한 경우 serial.write("1"); // 1개를 보냅니다. println("1"); ) else ( //클릭이 없는 경우 serial.write(" 0" ); // 0을 보냅니다 ) )

이제 Arduino용 스케치를 작성해 보겠습니다.

문자 명령값; // 직렬 포트에서 오는 데이터 int ledPin = 13; // 내장 LED void setup() ( pinMode(ledPin, OUTPUT); // 데이터 출력 모드 Serial.begin(9600); ) void 루프() ( if (Serial.available()) ( commandValue = Serial.read ( ); ) if (commandValue == "1") ( digitalWrite(ledPin, HIGH); // LED 켜기 ) else ( digitalWrite(ledPin, LOW); // 그렇지 않으면 끄기 ) delay(10); // 다음 데이터 읽기 전에 지연)

두 스케치를 모두 실행해 보겠습니다. 창 내부를 클릭하고 LED가 켜진 것을 확인합니다. 클릭할 수도 없지만 마우스 버튼을 계속 누르고 있으면 LED가 계속 켜져 있습니다.

데이터 교환

이제 두 가지 접근 방식을 결합하고 보드와 애플리케이션 간에 양방향으로 메시지를 교환해 보겠습니다.

최대 효율성을 위해 부울 변수를 추가해 보겠습니다. 결과적으로 우리는 더 이상 Processing에서 지속적으로 1 또는 0을 보낼 필요가 없으며 직렬 포트가 언로드되고 불필요한 정보를 전송하지 않습니다.

보드가 보낸 단위를 감지하면 부울 값을 현재 상태( 낮은높은그 반대). 에 또 다른"1"을 찾을 수 없는 경우에만 보낼 "Hello Kitty" 문자열을 사용합니다.

기능 연락처 설정() Processing에서 수신할 것으로 예상되는 문자열을 보냅니다. 응답이 오면 Processing에서 데이터를 받을 수 있습니다.

문자 명령값; // 직렬 포트에서 오는 데이터 int ledPin = 13; 부울 ledState = 낮음; // LED 상태 제어 void setup() ( pinMode(ledPin, OUTPUT); Serial.begin(9600); setContact(); // 수신기가 응답하는 동안 접점에 바이트를 보냅니다. ) void loop() ( // 데이터를 읽을 수 있는 경우 if (Serial.available() > 0) ( // 데이터 읽기 commandValue = Serial.read(); if (commandValue == "1") ( ledState = !ledState; digitalWrite(ledPin, ledState ); ) delay(100) ; ) else ( // Serial.println("Hello Kitty"); ) delay(50); ) void setContact() ( while (Serial.available()<= 0) { Serial.println("A"); // отсылает заглавную A delay(300); } }

처리 스케치로 넘어 갑시다. 우리는 방법을 사용할 것입니다 직렬 이벤트(), 버퍼에서 특정 문자가 발견될 때마다 호출됩니다.

새 부울 변수 추가 먼저 연락, Arduino와 연결되어 있는지 확인할 수 있습니다.

방법에서 설정()라인 추가 serial.bufferUntil("\n");. 이를 통해 특정 문자를 찾을 때까지 들어오는 데이터를 버퍼에 저장할 수 있습니다. 이 경우에는 전송 중이므로 반환(\n)합니다. Serial.println()아두이노에서. "\N"끝에는 새 행을 활성화한다는 의미입니다. 즉, 이것이 우리가 보게 될 마지막 데이터가 됩니다.

우리는 지속적으로 데이터를 전송하기 때문에 방법 직렬 이벤트()주기 작업을 수행 그리다(), 비워둘 수 있습니다.

이제 주요 방법을 고려하십시오. 직렬 이벤트(). 새 줄(\n)을 입력할 때마다 이 메서드가 호출됩니다. 그리고 다음과 같은 일련의 작업이 수행될 때마다:

  • 들어오는 데이터를 읽습니다.
  • 값이 포함되어 있는지 확인합니다(즉, 빈 데이터 배열 또는 "null"이 전달되었는지 여부).
  • 공백 제거;
  • 필요한 데이터를 처음 수신한 경우 부울 변수 값을 변경합니다. 먼저 연락그리고 Arduino에게 새로운 데이터를 수신할 준비가 되었음을 알립니다.
  • 이것이 필요한 데이터 유형의 첫 번째 수신이 아닌 경우 콘솔에 표시하고 발생한 클릭에 대한 데이터를 마이크로 컨트롤러로 보냅니다.
  • 새로운 데이터 패킷을 받을 준비가 되었다고 Arduino에 알립니다.
import processing.serial.*; 시리얼 시리얼; // 직렬 포트 객체 생성 String 수신됨; // 직렬 포트에서 받은 데이터 // Arduino boolean에서 데이터 확인 firstContact = false; void setup() ( size(320, 120); String port = Serial.list(); serial = new Serial(this, port, 9600); serial.bufferUntil("\n"); ) void draw() ( ) void serialEvent(Serial myPort) ( // 수신된 데이터에서 문자열을 형성합니다. // "\n" - 구분 기호 - 수신된 데이터 패킷의 끝 = myPort.readStringUntil("\n"); // 확인 계속 진행하기 전에 데이터가 비어 있지 않다는 것을 확인하십시오. if (received != null) ( //공백 제거 Received = trim(received); 찾았으면 버퍼를 지우고 데이터 요청을 보냅니다 if (firstContact == false) ( if (received.equals("A")) ( serial.clear(); firstContact = true; myPort.write("A"); println ("contact"); ) ) else ( // 연락처가 설정되면 데이터를 가져와서 구문 분석합니다. println(received); if (mousePressed == true) ( ​​​​//창을 클릭한 경우 serial.write( "1"); //send 1 println(" 1"); ) // 모든 데이터가 있으면 새 패킷을 요청합니다. serial.write("A"); ) ) )

연결되어 실행되면 "Hello Kitty"라는 문구가 콘솔에 표시되어야 합니다. Processing 창을 클릭하면 핀 13의 LED가 켜지고 꺼집니다.

처리 외에도 PuTTy 프로그램을 사용하거나 포트 작업을 위해 기성 클래스를 사용하여 고유한 C# 프로그램을 작성할 수 있습니다.

04.통신: 디머

이 예는 LED의 밝기를 제어하기 위해 컴퓨터에서 보드로 데이터를 보내는 방법을 보여줍니다. 데이터는 0에서 255 사이의 단일 바이트 형식으로 제공됩니다. 데이터는 처리를 포함하여 직렬 포트에 액세스할 수 있는 컴퓨터의 모든 프로그램에서 가져올 수 있습니다.

예를 들어 핀 9에 저항과 LED가 있는 표준 회로가 필요합니다.

아두이노용 스케치.

Const int ledPin = 9; // 핀 9의 LED void setup() ( Serial.begin(9600); // 핀의 모드 설정 pinMode(ledPin, OUTPUT); ) void loop() ( 바이트 밝기; // 데이터가 있는지 확인 컴퓨터 if (Serial.available()) ( // 0에서 255까지의 마지막 수신 바이트를 읽습니다. 밝기 = Serial.read(); // LED의 밝기를 설정 analogWrite(ledPin, 밝기); ) )

처리용 코드

가져오기 처리.serial.*; 직렬 포트; void setup() ( size(256, 150); println("Available serial ports:"); println(Serial.list()); // 이 목록의 첫 번째 포트(숫자 0)를 사용합니다. port // Arduino 보드에 해당합니다. 마지막 매개변수(예: 9600)는 // 통신 속도입니다. // Arduino 스케치에서 Serial.begin()에 전달된 값과 일치해야 합니다. port = new Serial (this, Serial.list(), 9600); // 아두이노 보드에서 사용하는 포트 이름을 안다면 명시적으로 //port = new Serial(this, "COM1", 9600); ) void draw( ) ( // 검정색에서 흰색으로 그라데이션을 그립니다. for (int i = 0; i

생성된 창 위로 마우스를 실행하고 원하는 방향으로 이동합니다. 왼쪽으로 이동하면 LED의 밝기가 감소하고 오른쪽으로 이동하면 증가합니다.

04.통신: PhysicalPixel (마우스로 LED 켜기)

문제를 조금 바꿔보자. 사각형 위로 마우스를 이동하고 문자 "H"(높음)를 보내 보드의 LED를 켭니다. 마우스가 사각형 영역을 벗어나면 문자 "L"(낮음)을 보내 LED를 끕니다.

아두이노용 코드.

Const int ledPin = 13; // LED용 핀 13 int IncomingByte; // 데이터 수신을 위한 변수 void setup() ( Serial.begin(9600); pinMode(ledPin, OUTPUT); ) void loop() ( // 데이터가 있는 경우 if (Serial.available() > 0) ( // 버퍼의 바이트 읽기 IncomingByte = Serial.read(); // 이것이 H 문자(ASCII 72)이면 LED를 켭니다. if (incomingByte == "H") ( digitalWrite(ledPin, HIGH); ) // 이것이 L 문자( ASCII 76)이면 LED를 끄십시오. if (incomingByte == "L") ( digitalWrite(ledPin, LOW); ) ) )

처리용 코드.

가져오기 처리.serial.*; 플로트박스X; 플로트박스Y; intbox크기=20; 부울 마우스 오버박스 = 거짓; 직렬 포트; void setup() ( size(200, 200); boxX = width / 2.0; boxY = height / 2.0; rectMode(RADIUS); println(Serial.list()); // Arduino 보드가 연결된 포트를 엽니다. (이 경우 #0) // Arduino가 사용하는 것과 동일한 속도로 포트를 열어야 합니다. (9600bps) port = new Serial(this, Serial.list(), 9600); ) void draw() ( background(0) ); // 커서가 사각형 위에 있는 경우 if (mouseX > boxX - boxSize && mouseX boxY - boxSize && mouseY

04.커뮤니케이션: 그래프 (그래프 그리기)

이전 예에서 컴퓨터에서 보드로 데이터를 보낸 경우 이제 역 작업을 수행합니다. 전위차계에서 데이터를 수신하여 그래프 형태로 표시합니다.

일반적으로 Arduino는 진정한 작업 병렬화 또는 멀티스레딩을 지원하지 않습니다. 그러나 주기를 반복할 때마다 가능합니다. 고리()마이크로컨트롤러에 추가 백그라운드 작업을 실행할 시간인지 확인하도록 지시합니다. 이 경우 사용자는 여러 작업이 동시에 수행되는 것처럼 보일 것입니다.

예를 들어, 주어진 주파수에서 LED를 깜박이는 동시에 피에조 이미터에서 사이렌과 같은 상승 및 하강 소리를 방출한다고 가정해 보겠습니다. 우리는 이미 LED와 압전 이미 터를 Arduino에 두 번 이상 연결했습니다. 그림과 같이 회로를 조립해 봅시다.

LED를 "13"이 아닌 다른 디지털 핀에 연결하는 경우 220옴 전류 제한 저항을 잊지 마십시오.

2 LED 및 피에조 부저 제어 delay() 연산자 사용

이 스케치를 작성하여 Arduino에 업로드해 보겠습니다.

Const int soundPin = 3; /* 압전소자가 연결된 핀 번호로 변수 선언 */ const int ledPin = 13; // LED 핀 번호로 변수 선언 무효 설정()(핀모드(사운드핀, 출력); // 핀 3을 출력으로 선언합니다. 핀모드(LED핀, 출력); // 핀 13을 출력으로 선언합니다. } 무효 루프() (// 사운드 제어: tone(soundPin, 700); // 700Hz의 주파수로 소리를 낸다. delay(200); 톤(사운드핀, 500); // 500Hz에서 지연(200); 톤(사운드핀, 300); // 300Hz에서 지연(200); 톤(사운드핀, 200); // 200Hz에서 지연(200); // LED 제어: digitalWrite(ledPin, HIGH); // 화재 지연(200); 디지털 쓰기(LED 핀, LOW); // 소멸 지연(200); }

전원을 켜면 스케치가 필요한 만큼 정확하게 실행되지 않는 것을 볼 수 있습니다. 사이렌이 완전히 작동할 때까지 LED가 깜박이지 않고 LED가 깜박이기를 원합니다. ~ 동안사이렌 소리. 여기서 문제가 무엇입니까?

사실이 문제는 일반적인 방법으로 해결할 수 없습니다. 작업은 마이크로 컨트롤러에 의해 엄격하게 순차적으로 수행됩니다. 운영자 지연()지정된 시간 동안 프로그램의 실행을 지연시키며, 이 시간이 만료될 때까지 프로그램의 다음 명령은 실행되지 않습니다. 이 때문에 루프의 각 작업에 대해 다른 실행 기간을 설정할 수 없습니다. 고리()프로그램들. 따라서 어떻게든 멀티태스킹을 시뮬레이션해야 합니다.

3 병렬 프로세스"delay()" 연산자 없이

Arduino가 유사 병렬로 작업을 수행하는 옵션은 Arduino 개발자가 제안합니다. 이 방법의 핵심은 주기를 반복할 때마다 고리() LED를 깜박일 시간(백그라운드 작업 수행)인지 여부를 확인합니다. 그렇다면 LED의 상태를 반전시킵니다. 이것은 일종의 우회 연산자입니다. 지연().

Const int soundPin = 3; // 압전 소자의 핀 번호가 있는 변수 const int ledPin = 13; // LED 핀 번호가 있는 변수 const long ledInterval = 200; // LED 깜박임 간격, msec. int ledState = 낮음; // LED unsigned의 초기 상태 long previousMillis = 0; // 이전 LED가 켜진 시간을 저장합니다. 무효 설정()(핀모드(사운드핀, 출력); // 핀 3을 출력으로 설정합니다. 핀모드(LED핀, 출력); // 핀 13을 출력으로 설정합니다. } 무효 루프() (// 사운드 제어: tone(soundPin, 700); 지연(200); 톤(사운드핀, 500); 지연(200); 톤(사운드핀, 300); 지연(200); 톤(사운드핀, 200); 지연(200); // LED 깜박임: // Arduino가 켜진 이후의 시간, ms: unsigned long currentMillis = millis(); // 깜박일 시간이면 if (currentMillis - previousMillis >= ledInterval) ( previousMillis = currentMillis; // 현재 시간 저장 if (ledState == LOW) ( // LED 상태 반전 ledState = HIGH; ) else ( ledState = LOW; ) digitalWrite(ledPin, ledState); // LED 상태 토글 ) }

이 방법의 중요한 단점은 LED 제어 블록 앞의 코드 섹션이 "ledInterval" LED 깜박임 시간 간격보다 빠르게 실행되어야 한다는 것입니다. 그렇지 않으면 깜박임이 필요한 것보다 덜 자주 발생하고 작업의 병렬 실행 효과를 얻지 못합니다. 특히 스케치에서 사이렌 소리의 변화 지속 시간은 200+200+200+200 = 800ms이고 LED의 깜박임 간격은 200ms로 설정했습니다. 그러나 LED는 우리가 설정한 것의 4배인 800ms 주기로 깜박일 것입니다.

일반적으로 코드에서 연산자를 사용하는 경우 지연(), 이 경우 유사 병렬성을 시뮬레이션하기 어려우므로 피하는 것이 바람직합니다.

이 경우 사이렌 소리 제어 장치도 시간이 되었는지 여부를 확인하고 사용하지 않을 필요가 있습니다. 지연(). 그러나 이것은 코드의 양을 증가시키고 프로그램의 가독성을 악화시킬 것입니다.

4 ArduinoThread 라이브러리 사용병렬 스레드 생성

문제를 해결하기 위해 멋진 라이브러리를 사용할 것입니다. 아두이노 스레드, 의사 병렬 프로세스를 쉽게 만들 수 있습니다. 비슷한 방식으로 작동하지만 시간을 확인하는 코드를 작성할 수 없습니다. 이 주기에서 작업을 완료해야 하는지 여부입니다. 이것은 코드의 양을 줄이고 스케치의 가독성을 향상시킵니다. 작동 중인 라이브러리를 확인해 보겠습니다.


먼저 공식 웹사이트에서 라이브러리 아카이브를 다운로드하여 디렉토리에 압축을 풉니다. 도서관/아두이노 IDE 개발 환경. 그런 다음 폴더 이름을 바꿉니다. Arduino 스레드 마스터안에 아두이노 스레드.

배선도는 그대로 유지됩니다. 프로그램 코드만 변경됩니다.

#포함 // ArduinoThread 라이브러리 연결 const int soundPin = 3; // 압전 소자의 핀 번호가 있는 변수 const int ledPin = 13; // LED 핀 번호가 있는 변수 Thread ledThread = Thread(); // LED를 제어하는 ​​스레드를 생성합니다. Thread soundThread = Thread(); // 사이렌에 대한 제어 흐름 생성 무효 설정()(핀모드(사운드핀, 출력); // 핀 3을 출력으로 선언합니다. 핀모드(LED핀, 출력); // 핀 13을 출력으로 선언합니다. ledThread.onRun(ledBlink); // 스레드에 작업 할당 ledThread.setInterval(1000); // 응답 간격 설정, ms soundThread.onRun(sound); // 스레드에 작업 할당 soundThread.setInterval(20); // 응답 간격을 ms로 설정 } 무효 루프() (// LED를 토글할 시간인지 확인: if (ledThread.shouldRun()) ledThread.run(); // 스레드 시작 // 사이렌 소리를 변경할 시간인지 확인: if (soundThread.shouldRun()) soundThread.run(); // 스레드 시작 } // LED 플럭스: 무효 ledBlink() (정적 부울 ledStatus = 거짓; // LED 상태 켜짐/꺼짐 ledStatus = !ledStatus; // 상태 반전 digitalWrite(ledPin, ledStatus); // LED 켜기/끄기 } // 사이렌 스트림: 공허한 소리() (정적 int 톤 = 100; // 소리 톤, Hz tone(soundPin, ton); // "ton" Hz에서 사이렌을 켭니다. if (ton )

프로그램에서 두 개의 스레드를 만듭니다. 주도 스레드그리고 사운드 스레드, 각각은 자체 작동을 수행합니다. 하나는 LED를 깜박이고 두 번째는 사이렌 소리를 제어합니다. 각 스레드에 대한 루프의 각 반복에서 실행 시간이 왔는지 여부를 확인합니다. 도착하면 메서드를 사용하여 실행을 시작합니다. 운영(). 가장 중요한 것은 연산자를 사용하지 않는 것입니다. 지연(). 자세한 설명은 코드에 나와 있습니다.


코드를 Arduino 메모리에 로드하고 실행합니다. 이제 모든 것이 제대로 작동합니다!

프로젝트를 구현하는 동안 여러 인터럽트가 필요할 수 있지만 각각의 인터럽트가 최대 우선순위를 갖는다면 실제로 어떤 기능도 이를 갖지 않습니다. 같은 이유로 12개 이상의 인터럽트를 사용하지 않는 것이 좋습니다.

처리기는 시간 간격에 대한 최대 민감도를 갖는 프로세스에만 적용해야 합니다. 프로그램이 인터럽트 핸들러에 있는 동안 다른 모든 인터럽트는 비활성화된다는 것을 잊지 마십시오. 많은 수의 중단으로 인해 응답이 저하됩니다.

하나의 인터럽트가 활성화되고 나머지는 비활성화되는 순간 회로 설계자가 고려해야 하는 두 가지 중요한 뉘앙스가 있습니다. 첫째, 중단 시간은 가능한 한 짧아야 합니다.

이렇게 하면 다른 모든 예약된 인터럽트가 누락되지 않습니다. 둘째, 인터럽트를 처리할 때 프로그램 코드는 다른 인터럽트의 활동을 요구하지 않아야 합니다. 이것이 방지되지 않으면 프로그램이 단순히 정지됩니다.

긴 처리를 사용하지 마십시오 고리() , 변수가 volatile로 설정된 인터럽트 핸들러용 코드를 개발하는 것이 좋습니다. 더 이상의 처리가 필요하지 않음을 프로그램에 알립니다.

함수 호출의 경우 업데이트() 필요한 경우 먼저 상태 변수를 확인해야 합니다. 추가 처리가 필요한지 여부를 결정합니다.

타이머 구성을 시작하기 전에 코드를 확인해야 합니다. Anduino 타이머는 리소스가 3개뿐이고 다양한 기능을 수행하는 데 사용되기 때문에 제한된 리소스에 귀속되어야 합니다. 타이머 사용과 혼동하면 여러 작업이 단순히 작동을 멈출 수 있습니다.

특정 타이머가 작동하는 기능은 무엇입니까?

Arduino Uno 마이크로컨트롤러의 경우 3개의 타이머 각각에는 자체 작동이 있습니다.

그래서 타이머0 다섯 번째 및 여섯 번째 핀의 PWM 기능을 담당합니다. 밀리() , 마이크로() , 지연() .

또 다른 타이머 - 타이머1, 라이브러리와 함께 9번째 및 10번째 핀에서 PWM과 함께 사용 WaveHC와 서보.

타이머2 핀 11 및 13의 PWM과 함께 작동합니다. 음정.

회로 설계자는 공유 데이터의 안전한 사용을 처리해야 합니다. 결국 인터럽트는 밀리초 동안 모든 프로세서 작업을 중지하고 데이터 교환은 고리() 인터럽트 핸들러는 영구적이어야 합니다. 컴파일러가 최대 성능을 달성하기 위해 코드 최적화를 시작할 때 상황이 발생할 수 있습니다.

이 프로세스의 결과는 주요 코드 변수의 복사본을 레지스터에 저장하여 최대 액세스 속도를 보장합니다.

이 프로세스의 단점은 실제 값이 저장된 복사본으로 대체되어 기능이 손실될 수 있다는 것입니다.

이를 방지하려면 변수를 사용해야 합니다. 휘발성 , 불필요한 최적화를 방지하는 데 도움이 됩니다. 업데이트 주기가 필요한 대형 어레이를 사용하는 경우 이러한 업데이트 시 인터럽트를 비활성화해야 합니다.