임베디드 시스템을위한 스레드 대안
저는 현재 전기 공학을 공부하고 있습니다. 전염병으로 인해 수업이 중단되었고 이번에는 전자 및 프로그래밍에 대해 더 많이 배우고 있습니다.
저는 현재 Pic16f628a
일부 기능이있는 디지털 시계를 만들기 위해 일반 디지털 디스플레이 를 사용하려고 합니다. 문제는 시계가 표시되는 동안 실행 시간에 버튼을 눌러 메뉴에 액세스해야한다는 것입니다. 일반적으로 나는 시계 디스플레이에 대한 스레드를 호출하고 주 스레드는 입력을 감시하지만 그림 컨트롤러의 단순성으로 인해 리소스를 사용할 수 없습니다.
따라서 내 C 코드 (아직 그림에 특별히 구현되지 않음)는 다음과 같습니다.
void display_timer(){
static struct current_time timer;
static int is_time_set = 0;
set_current_time(&timer, &is_time_set);
while (is_time_set){
system("clear");
printf("########\n");
printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
printf("########\n");
sleep(1);
update_timer(&timer, &is_time_set);
}
}
int main ()
{
while (1){
display_menu();
}
}
sleep () 동안 컨트롤러는 새로운 입력을 감시하고 그에 따라 행동 할 수 있어야합니다.
한 가지 대안은 상태 머신을 사용하여 버튼 누름을 저장하고 절전 기능을 4 또는 8 간격으로 나누는 것입니다.
while (is_time_set){
system("clear");
printf("########\n");
printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
printf("########\n");
for (int i = 0; i<8; i++){
if (state_machine_input == 1){state_machine_input = 0; break;}
sleep(1/8);
}
update_timer(&timer, &is_time_set);
그것은 할 수 있지만, 예를 들어 다른 상태 머신을 추가하는 등 프로젝트에 더 많은 복잡성을 추가 할 필요가 없다면 감사하겠습니다. 이 기능을 구현하기 위해 소프트웨어 열에서 무엇을 할 수 있습니까?
답변
스레딩은 마이크로 컨트롤러 프로그래밍보다 높은 수준의 개념입니다. 간단히 말해서 스레드는 타이머 인터럽트를 사용하는 스케줄러로 구현되어 프로그램 카운터 + 스택 포인터 등을 저장하고 다른 위치로 설정합니다. 따라서 인터럽트를 사용하여 유사한 개념을 구현하는 것이 가능하고 쉽게 구현할 수 있습니다. 일반 멀티 스레딩 대신 특수 인터럽트를 얻을 수 있다는 이점이 있습니다.
이것은 스택 사용에 관해서는 극도로 제한적인 PIC와 같은 제한된 레거시 8 쓴맛을 사용하는 유일한 현명한 방법입니다. 마이크로 컨트롤러 용으로 작성된 스레드 라이브러리도 사용하지 마십시오. 그것은 아무것도 얻지 못한 채 과도한 부풀림과 복잡성을 더할뿐입니다. 일반적으로 PC 프로그래밍 개념을 임베디드 세계로 끌어들이는 것은 나쁜 생각입니다.
당신이 해야 할 일은 10ms마다 한 번씩 실행되는 주기적 타이머 인터럽트 내부에 버튼 스캔을 넣는 것입니다. 인터럽트 내부에서 디 바운싱을 위해 버튼을 폴링하고 이전에 읽은 버튼과 비교합니다. 그 결과는 주 프로그램과 공유되는 변수에 저장되고 volatile
경쟁 조건 으로 선언 되고 보호됩니다. 인터럽트 내부에서 변수에 쓰기 만하므로 읽기가 8 비트인지 확인하는 것으로 충분한 보호가 될 수 있지만 확실히하려면 디스 어셈블해야합니다. 여기에 대한 자세한 정보 : 임베디드 C 개발에서 휘발성 사용 .
인터럽트 사용
버튼을 누를 때 코드를 실행하고 싶습니까? 핀 변경 인터럽트 사용
일정한 간격으로 무언가를하고 싶습니까? 타이머 인터럽트 사용
어떤면에서 마이크로 컨트롤러의 하드웨어는 인터럽트 소스를 모니터링하는 '스레드'를 실행하고 각 이벤트에 대해 '콜백'또는 인터럽트 루틴을 실행합니다.
메인 프로그램은 인터럽트를 실행하는 동안 자동으로 일시 중지됩니다.
인터럽트와 메인 코드간에 데이터를 공유하는 일반적인 방법은 volatile
전역 변수를 통해 이러한 전역에서 데이터를 읽을 때 인터럽트가 컨트롤러의 워드 크기보다 클 때 일시적으로 비활성화하는 것입니다 (거의 항상 8 비트 컨트롤러에 있음).
나는 아마도 협력적인 멀티 태스킹 라이브러리를 제안 할 것이다. 내가 과거에 사용한 것은 Protothreads입니다.http://www.dunkels.com/adam/pt/
괜찮은 협력적인 멀티 태스킹 라이브러리는 사물을 추적하는 데 필요한 암시 적 상태 머신을 추상화하는 데 도움이됩니다.
행운을 빕니다.
임베디드 시스템과 관련하여 일반적으로 멀티 태스킹에는 다른 접근 방식이 있습니다.
- 폴링 또는 협력 적 멀티 태스킹 : 모든 작업이 하나의 무한 루프에서 수행되며 작업은 지연을 피하기 위해 가능한 최소한의 시간을 갖고 가능한 한 빨리 기본 실행으로 돌아가도록 설계되었습니다. 이 아키텍처에 적합한 작업은 상위 수준 개념의 관점에서 생각하는 것과 다를 수 있습니다. 예를 들어 애플리케이션에서 하나의 작업이 될 수
update_display
있고 다른 작업이 될 수 있으며 다음check_button
과 같은 루프를 구축 할 수 있습니다 .
while(1){
check_buttons();
update_display();
sleep(0.1); //seconds
}
인터럽트 : 하드웨어 인터럽트에 연결된 모든 가능한 입력과 기본 실행은 인터럽트에 넣을 수없는 항목에 대해 남겨집니다 (아무것도 아닐 수 있습니다.이 경우 일반적으로 마이크로 컨트롤러는 전력 소비를 줄이기 위해 절전 모드로 전환됩니다. 자세한 방법) 일반적으로 사용되는 특정 마이크로 컨트롤러 및 컴파일러에 따라 다릅니다.
RTOS : 마이크로 컨트롤러가 제공하는 전력량에 따라 작업 또는 스레드 생성을위한 API를 제공 할 수있는 RTOS (실시간 운영 체제)를 실행할 수 있습니다. 이것은 응용 프로그램 및 하드웨어 기능에 따라 다르며 교육용 예제가 필요하지 않아야합니다 (또는 권장, imo).
또한 응용 프로그램의 전체 아키텍처를 결정하는 데있어 또 다른 중요한 부분은 작업의 분할과 이들이 협력하는 방법이라는 점을 고려하십시오. 사용 된 패러다임 중 하나는 State Machines입니다 (링크는 압도적 일 수있는 일반 위키피디아 페이지로 연결되며, 임베디드 프로그래밍에 특화된보다 간단한 리소스는 교과서 또는 Google에서 찾을 수 있습니다).
대부분 8 비트 장치에는 소스가 제한되어 있습니다. 8 비트 PIC에서 더 간단한 솔루션이 더 나은 솔루션이라고 생각합니다.
두 가지 작업에 대한 하드웨어 타이머를 만들 수 있습니다. 플래그를 설정하고 무한 루프에서 플래그를 확인하고 작업을 수행하고 플래그를 재설정하십시오. 지연을 사용하지 마십시오. 이 방법은 플래그가 올라간 경우 무한 루프에서 작업을 수행하도록 보장합니다.
그러나 플래그가 올라갈 때 작업이 정확한 시간에 실행되지 않는다는 것을 알아야합니다. 동시에 두 개의 플래그가 설정되어 있다면 어느 것이 먼저 실행되는지 알 수 없습니다. 무한 루프에서 어디에 있는지 모르기 때문입니다. 그러나 시간이 중요 하지 않은 인터페이스 응용 프로그램 에는 대부분 괜찮습니다 .