제로 크로싱 활성화 릴레이


13

제로 크로싱 전력에서 트리거되는 스위치 (솔리드 스테이트 릴레이 또는 트라이 액 기반)를 프로그래밍하려면 어떻게해야합니까?

이 주제에 익숙하지 않은 경우 : 전원 선의 사인파가 0을 넘어 서면 230V 전원을 켭니다. 그 결과 전류의 급격한 급상승으로 인한 전자기 장애가 최소화됩니다.

특히, 가능한 한 많은 소프트웨어를 사용하는 것이 좋습니다. 레벨 및 전류를 점검하기위한 소형 변압기, 다이오드 및 커플 저항으로 구성된 감지 회로는 AC 입력 전원이 양의 절반 일 때 "1", 음의 경우 "0"을 입력 GPIO 핀에 연결합니다. 출력은 몇 개의 솔리드 스테이트 릴레이와 출력 GPIO 핀에 연결된 풀업 등을 유지하기위한 필수 요소로 구성됩니다.

The problem is timing: with 50Hz AC we get 100 zero-crossings in a second, one half-cycle is 10ms. To get within reasonable distance from zero-crossing to keep said EMI low we shouldn't activate the output more than 10% past (or before) the event of zero-crossing, that means +-1ms tolerance. That doesn't mean 1ms reaction time - we can reasonably expect the next zero-crossing to occur precisely 10ms after the first one, or the fourth - 40ms. It's about granularity - if we allow 20ms for reaction, it must be between 19 and 21ms, not 18 or 22.

입력이 에지를 감지하기 때문에 1ms 이내에 또는 그 이후 10ms의 고정 배수 내에서 이러한 타이머-트리거 출력 GPIO를 어떻게 구현할 수 있습니까-가급적이면 일부 음의 바이어스 (변압기와 릴레이가 1.6ms 지연을 허용 함); 그래서 입력 펄스 이후로 트리거가 8.4+ (n * 10) ms 가량 떨어지기를 원합니다. 바이어스는 회로에 의해 발생 된 지연에 대응합니다.)-물론 "사용자 요구에 따라", 사용자는 "1 "를 / sys / class / ... 파일로 보내고 가장 가까운 (거의) 기회에 출력이"on "됩니다. 사용자가 "0"을 쓰고 제로 크로싱에 도달하면 특정 릴레이가 해제됩니다.

커널 모듈을 작성하거나 해킹해야한다고 생각합니다. 커널에서 Raspberry Pi의 GPIO 핀을 처리하는 기능과 이러한 기능을 얻기 위해 어떤 종류의 타이머를 부착 할 수 있습니까?


당신이 이야기하는 매우 흥미로운 프로젝트! 대략적인 추정치 : 먼저 슈미트 트리거 로직을 통해 50Hz 원래 신호에서 사인파를 GPIO로 인터페이스합니다. 거기에서 신호의 상승 또는 하강 에지에 인터럽트가 발생합니다. 이제 50Hz AC에 고정되어 다음 제로 크로싱이 발생할 때 '예측'할 수 있습니다. 확실히 이것은 커널 드라이버 프로그래밍과 관련이 있습니다. Google은 당신의 친구입니다 :-)
sparkie

Inmojo의 AC 디머 모듈을 살펴보십시오 . 오픈 소스 문서를 사용하여 프로젝트에 대해 이것을 성공적으로 복제했습니다. 코드의 논리를 이해하는 데 도움이되는 Arduino 샘플 코드도 있습니다.
버터

@ 버터 스 : Arduino 프로그래밍과 Linux Kernel 모듈 프로그래밍의 차이가 소프트웨어 측면을 쓸모 없게 만들지 두려워하지만 하드웨어 회로도는 내가 필요한 것의 100 %를 차지합니다. 감사합니다. 두 프로젝트의 차이점은 소프트웨어에만 있습니다 (디 머는 트라이 액을 주기적으로 전환해야하지만 스위치는 스위치를 전환 할 때마다 한 번만 전원을 켜고 끄는 것입니다).
SF.

하드웨어 측면은 물론 100 %입니다.
SF.

답변:


6

커널을 해킹 할 필요는 없습니다. 스케줄러 큐에서 프로세스를 이동하기 만하면됩니다.

    #include<sched.h>

    struct sched_param param;               
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);
    if( sched_setscheduler( 0, SCHED_FIFO, &param ) == -1 )
    {
            perror("sched_setscheduler");
            return -1;
    }

지금부터 프로세스는 cat /proc/sys/kernel/sched_rt_runtime_uscat /proc/sys/kernel/sched_rt_period_us밀리 초 시간 세그먼트에서 밀리 초를 받고, 그 시간 동안 선점 할 위험없이 중단없이 실행합니다 (실제로 기본적으로 BerryBoot : 기본적으로 초당 0.95 초). 이러한 가치를 지니고 있지만 여기서는 더 많은 목적이 필요하지 않습니다.

clock_gettime()지연 시간을 클럭하기 위해 밀리 초 (필요한 정밀도에 관한)로 타이머 기능을 사용하고 있습니다.

호출 timer(1)하면 재설정되고 호출 timer(0)은 재설정 이후 시간을 반환합니다.

    #include<time.h>
    typedef unsigned long long ulong64;

    ulong64 timer(unsigned char reset)
    {
            struct timespec t;
            static struct timespec lt={0,0};
            clock_gettime(CLOCK_REALTIME, &t);
            if(reset)
            {
                    lt.tv_sec = t.tv_sec;
                    lt.tv_nsec = t.tv_nsec;
            }

            int r = ((ulong64)(t.tv_sec - lt.tv_sec))*1000 + (t.tv_nsec - lt.tv_nsec)/1000000;

            return r;
    }

rt이를 컴파일 -lrt하려면 gcc 명령에 추가 하기 위해 라이브러리 와 연결해야합니다 .

이제 메인 루프입니다. "사용자 요청"에 스위치 입력을 사용하고 있지만 네트워크, 타이머 등을 사용할 수 있습니다. 부울 값을로 가져 오기만하면됩니다 in.

    while(1)
    {
            //when idle, return a lot of CPU time back to the system. 
            //A call every 100ms is perfectly sufficient for responsive reaction.
            usleep(100000); 

            in  = bcm2835_gpio_lev(SWITCH_PIN);
            out = bcm2835_gpio_lev(TRIAC_PIN);

            if(in==out) continue;   //nothing to do; wait user input, return control to system.

            //The output needs to be changed.
            //First, let's wait for zero-crossing event.
            timer(TIMER_RESET);
            zx = bcm2835_gpio_lev(ZEROXING_PIN);

            //We don't want to freeze the system if the zero-xing input is broken.
            //If we don't get the event within reasonable time, 
            // (like three half-sines of the power; ZEROXING_TIMEOUT = 70)
            // we're going to bail.
            while(timer(TIMER_READ) < ZEROXING_TIMEOUT)
            {
                    if(zx != bcm2835_gpio_lev(ZEROXING_PIN))
                    {
                            //Event detected.                  
                            timer(TIMER_RESET);
                            break;
                    }
            }
            if(timer(TIMER_READ) >= ZEROXING_TIMEOUT) continue;     //Zero-crossing detection is broken, try again soon.

            //Now we are mere milliseconds after zero-crossing event arrived
            // (but it could have taken some time to arrive) so let's wait for the next one, making adjustments for the system delay.
            // This is to be worked out using an oscilloscope and trial and error.
            // In my case BIASED_DELAY = 19.

            while(timer(TIMER_READ)<BIASED_DELAY) ;

            //We can reasonably expect if we perform this right now:
            bcm2835_gpio_set_pud(TRIAC_PIN, in);
            //the signal will reach the output right on time.

            // The 100ms delay on return to start of the loop should be enough 
            // for the signals to stabilize, so no need for extra debouncing.
    }

메인 a / c에 파이 제어 디머 스위치를 구현할 때 이것이 효과가 있습니까? 난 그냥을 설정하는 대신) I)가 1이 아닌 100ms마다의 훨씬 작은 뭔가 ()와 2 해상도를 변경 것이라고 상상 TRIAC_PIN하는 in, 내가 설정해야 할 것 TRIAC_PIN, 1에 비례하여 미리 설정된 시간을 (대기 원하는 디머 레벨)을 누른 다음 TRIAC_PIN다시 0으로 설정하십시오 .
rinogo

메인 루프에서 줄 if(in==out) continue;을 으로 변경하고 싶습니다 if(out==0) continue;. 실제로, 나는 pi 프로그래밍에 완전히 익숙하지 않으므로 아마도 필요하지 않을 것입니다-이것이 모두 동 기적으로 일어나고 있다고 생각합니다 (즉, 중첩 루프가 여전히 실행되는 동안 메인 루프가 호출되는 것에 대해 걱정할 필요가 없습니다)
rinogo

(이것은 모두 위에서 언급 한 Inmojo 조광기 모듈을 사용하고 있습니다 : inmojo.com/store/inmojo-market/item/… )
rinogo

2
문제가 있습니다. 안정적인 시스템 활동을 위해서는 주기적으로 시스템을 제어해야하며 20ms 미만의 짧은 시간 내에 시스템을 복원해야한다고 생각합니다. 따라서 이러한 수율로 인해 펄스가 누락되고 전구가 깜박입니다. 나는 물었다 그것에 대해 질문을했지만 답변을 얻지 않았다. 시스템 선점을 완전히 비활성화하기 위해 sched_rt_runtime_us 및 sched_rt_period_us를 모두 -1로 설정할 수 있지만 sched_yield () 또는 usleep ()을 전혀 사용하지 않으면 문제가 발생할 수 있습니다.
SF.

2
즉, SCHED_FIFO를 사용하면 시간 조각을 시작하면 자발적으로 산출 할 때까지 (또는 sched_rt_runtime_us가 경과 할 때까지) 중단되지 않고 지속되지만 시스템은 해당 시간 조각을 얻을 를 보장하지 않습니다 . 필자의 경우 정상적인 작동에서 호출 사이의 시간 (작업에 시간 조각 제공)이 최대 CPU로드로 0.1s까지 연장 될 수 있음을 알았습니다. 어쩌면 그 기간을 미세 조정하고 더 짧게 할 수는 있지만 어떻게 해야할지 모르겠습니다.
SF.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.