Rơle kích hoạt xuyên không


13

Làm thế nào tôi có thể đi về lập trình một công tắc (dựa trên rơle trạng thái rắn hoặc triac) kích hoạt năng lượng xuyên không?

Đối với những người không quen thuộc với chủ đề này: Bật nguồn 230V, khi sóng hình sin của đường dây điện bằng 0 - kết quả là giảm thiểu các nhiễu điện từ do dòng điện tăng đột biến.

Cụ thể, tôi muốn chuyển càng nhiều vào phần mềm càng tốt. Mạch phát hiện bao gồm một máy biến áp nhỏ, một diode và một vài điện trở để kiểm tra mức và dòng điện cung cấp "1" khi công suất đầu vào AC ở một nửa dương, "0" âm, được gắn vào chân GPIO đầu vào. Đầu ra bao gồm một vài rơle trạng thái rắn và các yếu tố cần thiết để giữ cho chúng chạy (pull-up, v.v.), được gắn vào các chân GPIO đầu ra.

Vấn đề là thời gian: với 50Hz AC, chúng ta có được 100 điểm giao nhau trong một giây, một nửa chu kỳ là 10ms. Để có được khoảng cách hợp lý từ giao nhau bằng 0 để giữ EMI ở mức thấp, chúng ta không nên kích hoạt đầu ra quá 10% (hoặc trước đó) sự kiện giao nhau bằng 0, nghĩa là dung sai + -1ms. Điều đó không có nghĩa là thời gian phản ứng 1ms - chúng ta có thể mong đợi một cách hợp lý việc vượt 0 tiếp theo xảy ra chính xác là 10ms sau lần đầu tiên hoặc lần thứ tư - 40ms. Đó là về độ chi tiết - nếu chúng ta cho phép 20ms cho phản ứng, thì nó phải nằm trong khoảng từ 19 đến 21ms chứ không phải 18 hoặc 22.

Làm cách nào tôi có thể triển khai GPIO đầu ra kích hoạt bộ hẹn giờ như vậy trong vòng 1ms kể từ khi đầu vào phát hiện ra một cạnh hoặc trong bội số cố định 10ms kể từ đó - tốt nhất là với trợ cấp cho một số sai lệch âm (giả sử, biến áp và rơle giới thiệu độ trễ 1.6ms; vì vậy tôi muốn kích hoạt tắt 8.4+ (n * 10) ms kể từ xung đầu vào, theo cách đó, độ lệch sẽ chống lại độ trễ do mạch giới thiệu.) - tất nhiên là "theo yêu cầu của người dùng", giả sử, người dùng viết "1 "đến tệp / sys / class / ... và trong cơ hội (gần nhất) gần nhất, đầu ra sẽ" bật ". Người dùng viết "0" và khi giao nhau bằng 0 xuất hiện, ngắt tiếp sức cụ thể.

Tôi tin rằng điều này sẽ yêu cầu viết hoặc hack một mô-đun hạt nhân. Bạn có thể chỉ cho tôi cách xử lý các chân GPIO của Raspberry Pi trong kernel không, và tôi có thể gắn loại bộ hẹn giờ nào cho nó (trừ khi đã có sẵn một số chức năng) để có được loại chức năng này?


dự án khá thú vị mà bạn nói về! Chỉ để đưa ra một ước tính sơ bộ: Trước tiên tôi sẽ giao tiếp sóng hình sin từ tín hiệu gốc 50Hz thông qua logic kích hoạt schmitt sang GPIO. Từ đó tạo ra một ngắt trên cạnh tăng hoặc giảm của tín hiệu. Bây giờ bạn bị khóa trên 50Hz AC và có thể 'dự đoán' khi xảy ra giao thoa 0 tiếp theo. Chắc chắn điều này liên quan đến một số chương trình trình điều khiển hạt nhân. Google là bạn của bạn :-)
Sparkie

Hãy xem mô-đun mờ AC của Inmojo . Tôi đã nhân bản thành công điều này cho một dự án bằng tài liệu nguồn mở của họ. Ngoài ra còn có một số mã mẫu Arduino có thể giúp bạn thông qua logic của mã của bạn.
Butters

@Butter: Tôi sợ khoảng cách giữa lập trình Arduino và lập trình mô-đun Linux Kernel sẽ khiến phần mềm trở nên vô dụng đối với tôi, nhưng sơ đồ phần cứng bao gồm 100% những gì tôi cần - cảm ơn, bạn đã tiết kiệm được khá nhiều công việc của tôi - sự khác biệt giữa hai dự án chỉ nằm ở phần mềm (bộ điều chỉnh độ sáng phải chuyển đổi ba vòng theo chu kỳ trong khi công tắc chỉ bật / tắt một lần cho mỗi lần bật công tắc.)
SF.

Tất nhiên là 100% phần cứng.
SF.

Câu trả lời:


6

Bạn không cần phải hack kernel. Bạn chỉ cần di chuyển quá trình ra khỏi hàng đợi lập lịch.

    #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;
    }

Từ giờ, quy trình của chúng tôi nhận được cat /proc/sys/kernel/sched_rt_runtime_usmili giây trong mỗi cat /proc/sys/kernel/sched_rt_period_usphân đoạn thời gian mili giây, thực hiện không bị gián đoạn mà không có nguy cơ bị đánh cắp trước trong thời gian đó (theo thực tế, theo mặc định trên BerryBoot: 0,95 giây mỗi giây.) Nếu bạn cần nhiều hơn, hãy lộn xộn với những giá trị này, nhưng tôi không cần nhiều hơn cho mục đích của mình ở đây.

Tôi đang sử dụng chức năng hẹn giờ tính bằng mili giây (đó là về độ chính xác tôi cần) dựa trên clock_gettime()đồng hồ độ trễ của tôi.

Gọi timer(1)lại đặt lại nó, gọi timer(0)trả lại thời gian kể từ khi thiết lập lại.

    #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;
    }

Bạn cần liên kết với rtthư viện để biên dịch - thêm -lrtvào lệnh gcc của bạn.

Bây giờ, cho vòng lặp chính. Tôi đang sử dụng đầu vào chuyển đổi cho "yêu cầu người dùng" nhưng bạn có thể sử dụng mạng, hẹn giờ hoặc bất cứ điều gì. Tất cả bạn cần là để có được giá trị boolean vào 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.
    }

Điều này có hoạt động để thực hiện một công tắc điều chỉnh độ sáng điều khiển pi cho nguồn điện a / c không? Tôi tưởng tượng rằng tôi sẽ phải 1) thay đổi độ phân giải thành một cái gì đó nhỏ hơn nhiều (thay vì cứ sau 100ms) và 2) thay vì chỉ cài đặt TRIAC_PINthành in, tôi sẽ phải đặt thành TRIAC_PIN1, đợi một khoảng thời gian xác định (theo tỷ lệ mức độ mờ mong muốn), và sau đó đặt TRIAC_PINlại về 0. Điều này có hoạt động không?
rinogo

Tôi cho rằng trong vòng lặp chính, tôi cũng muốn thay đổi dòng if(in==out) continue;thành if(out==0) continue;, phải không? Trên thực tế, tôi hoàn toàn mới với lập trình cho pi, vì vậy có lẽ điều đó không cần thiết - tôi đoán tất cả điều này xảy ra đồng bộ (nghĩa là chúng ta không phải lo lắng về vòng lặp chính được gọi trong khi các vòng lặp lồng nhau vẫn đang thực thi)
rinogo

(Tất cả đều sử dụng mô-đun mờ Inmojo đã nói ở trên, tất nhiên: inmojo.com/store/inmojo-market/item/ mẹo )
rinogo

2
Có một vấn đề với điều đó. Để hoạt động hệ thống ổn định, bạn PHẢI kiểm soát năng suất cho hệ thống theo định kỳ và tôi thực sự nghi ngờ bạn sẽ khôi phục nó trong thời gian ngắn nhất là (dưới) 20ms. Vì vậy, những sản lượng này sẽ dẫn đến các xung bị bỏ lỡ và kết quả là bóng đèn nhấp nháy. Tôi đã hỏi một câu hỏi về điều đó nhưng không có câu trả lời. Bạn có thể đặt cả calendar_rt_r nb_us và calendar_rt_apse_us thành -1 để vô hiệu hóa hoàn toàn trước khi thực hiện hệ thống, nhưng nếu bạn không lên lịch trình_yield () hoặc us ngủ (), điều đó chắc chắn sẽ gây ra vấn đề.
SF.

2
Đó là: với SCHED_FIFO khi bạn bắt đầu một lát cắt thời gian, nó sẽ không bị gián đoạn cho đến khi bạn tự nguyện (hoặc calendar_rt_r nb_us bị trôi qua) nhưng hệ thống không đảm bảo khi bạn có được lát cắt thời gian đó. Trong trường hợp của tôi, tôi nhận thấy trong hoạt động bình thường, thời gian giữa các cuộc gọi (đưa ra các lát thời gian cho tác vụ) có thể kéo dài đến 0,1 giây với tải CPU tối đa. Có lẽ khoảng thời gian đó có thể được điều chỉnh và buộc phải rút ngắn nhưng tôi không biết làm thế nào.
SF.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.