Điều gì khiến chương trình LED vi điều khiển của tôi ngừng hoạt động?


11

Vì vậy, tôi là một người hoàn thành và hoàn toàn mới làm quen với lập trình. Tôi đã thực hiện một số nội dung cơ bản trên Arduinos (nghĩa là bật đèn LED và hiển thị thứ gì đó trên màn hình LCD) và tôi đang cố gắng tự dạy mình cách lập trình trong C. Tôi là một kỹ sư phần cứng bằng thương mại, nhưng điều đó làm phiền tôi rằng tôi không thể làm bất kỳ phần mềm / phần mềm nào và không có khóa học buổi tối nào để dạy nó, và tôi muốn tiếp tục các lựa chọn nghề nghiệp của mình. Tôi đang đấu tranh để hiểu làm thế nào một số các lệnh này đi cùng nhau và đã gặp phải một vấn đề mà tôi không thể hiểu được tại sao nó không hoạt động.

Vì vậy, tôi có một đầu vào và đầu ra. Đầu ra của tôi là bật cổng FET để bật đèn LED. Đầu vào đến từ một cổng AND. Vì vậy, đèn LED của tôi luôn sáng và khi tôi nhận được tín hiệu đầu vào từ cổng AND (đã đáp ứng 2 điều kiện), tôi muốn đầu ra (chuyển đổi LED) ở mức THẤP (tắt đèn LED. Vì đầu ra cũng được kết nối với một trong những đầu vào AND, điều này cũng sẽ biến tín hiệu đầu vào THẤP.

Điều tôi muốn làm: Tôi chỉ muốn đọc đầu vào là 'điều kiện được đáp ứng' và tắt đèn LED. Sau đó nên tắt trong 1 giây và bật lại. Nếu đầu vào trở lại CAO, quá trình lặp lại. Tôi đang sử dụng một nút ấn đơn giản để thực hiện chuyển đổi như đầu vào cổng AND khác và đã đo rằng đầu ra (đầu vào MCU) tăng cao khi nhấn nút, nhưng đèn LED bật (đầu ra) sẽ không tắt. Mã của tôi là (tôi nghĩ) khá đơn giản, nhưng rõ ràng tôi không hiểu một cái gì đó chính xác vì nó không hoạt động.

Vì vậy, đây là mã tôi đang sử dụng:

#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

int main() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
}

Và với tôi, điều đó có vẻ hợp lý. Ở trạng thái thông thường, đầu ra là CAO. Nếu đầu vào nhận được tín hiệu từ cổng AND, đèn LED sẽ tắt trong 1 giây, sau đó bật lại.

Tôi đã làm gì sai vì nó trông giống như cách hợp lý để làm điều đó và tôi không thể hiểu tại sao điều đó không hiệu quả?

Nếu nó giúp, tôi đang sử dụng Nucleo F103RB. Khi tôi sử dụng mã 'nhấp nháy' và chỉ bật và tắt đèn LED như vậy, nó sẽ hoạt động tốt, chỉ khi tôi thêm câu lệnh 'nếu' thì nó bị lỗi.

Đây là mạch đơn giản hóa:

sơ đồ

mô phỏng mạch này - Sơ đồ được tạo bằng CircuitLab

PS Tôi biết tôi đã không thêm chúng vào sơ đồ, nhưng cổng AND có điện trở kéo xuống trên đầu vào và đầu ra.


Nó có hoạt động không nếu bạn đặt "điều kiện đáp ứng" trực tiếp vào IN?
Transitor

Nó không. Tôi đã nhấn nút thẳng vào IN và vẫn không hoạt động
Tò mò

1
Đó là một ý tưởng tốt để đánh dấu các biến đầu vào là không ổn định hoặc trình biên dịch có thể thực hiện một số tối ưu hóa kỳ lạ bằng cách giả sử rằng nó không bị thay đổi từ bên ngoài mã.
Dirk Bruere

3
@DirkBruere: Bạn sẽ hy vọng định nghĩa DigitalInđã bao gồm volatile.
MSalters

3
Chỉ là một gợi ý cho lần tiếp theo: Hãy thử giữ nút xuống khi bạn bật (hoặc đặt lại) CPU (hoặc vi điều khiển). Bây giờ chuyện gì xảy ra?
một CVn

Câu trả lời:


26

Tôi đã nghĩ rằng bạn sẽ cần một vòng lặp xung quanh mã của bạn -

while(1)
{

    if (ip == 1){
       op = 0;
       wait (1.0);
       op = 1;}
    else {
       op = 1;}
}

Trước khi bạn có cơ hội nhấn nút, mã của bạn sẽ hoàn thành và thoát. Bạn cần một thời gian để giữ cho câu lệnh if liên tục chạy.


Điều gì làm cho điều đó khác biệt với tôi? Tôi có thể thấy "trong khi" nhưng điều đó làm gì? Xin lỗi cho tất cả các câu hỏi nhưng tôi thực sự đang bắt đầu với kiến ​​thức không!
Tò mò

1
@cantly Trước khi bạn có cơ hội nhấn nút, mã của bạn sẽ hoàn tất và thoát. Bạn cần một thời gian để giữ cho câu lệnh if liên tục chạy. Đây thường là trường hợp, trừ khi có một cái gì đó khác nhau về vi điều khiển bạn đang lập trình.
HandyHowie

9
"Bạn có thể giải thích lý do tại sao điều đó hoạt động không" - Mọi thứ trong một vòng lặp được lặp lại cho đến khi điều kiện giải quyết thành không. Điều kiện là gì, bạn có thể hỏi; đó là phần trong ngoặc đơn sau từ "while" và như bạn có thể thấy, điều kiện được đặt thành 1, vì vậy nó không bao giờ bằng 0 và do đó được lặp lại không xác định. Không có vòng lặp while, mã được thực thi chỉ một lần và sau đó phần mềm chấm dứt, nhưng với vòng lặp while, mã được thực thi liên tục cho đến khi bạn bật phần cứng.
Phụng vụ

14
Lỗi của bạn có lẽ xuất phát từ việc đi Arduino để mbed. Trong Arduino bạn thường đặt mã ứng dụng của mình vào loop(), nhưng khung Arduino bổ sung mã gần giống như vậy int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0

1
@Cantly Yours đã làm việc. Thật không may, nó chạy chính xác một lần, ngay lập tức khi bạn bật nó lên. Phải mất một micro giây để chạy, và đó là nó. Nếu bạn muốn nó tiếp tục kiểm tra đầu vào và thiết lập đầu ra, bạn cần nói với nó để tiếp tục thực hiện. "while (some_condition)" chạy miễn là "some_condition" là đúng, trong ngôn ngữ C có nghĩa là khác không. Vì vậy, "while (1)" tiếp tục kiểm tra đầu vào mãi mãi, hoặc ít nhất là miễn là nó vẫn được bật.
Graham

21
#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

int main() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
    // and now the program ends? What to do?
}

Bộ xử lý thực hiện các hướng dẫn tuần tự . Nó bắt đầu bằng một bước nhảy main()từ trong mã khởi tạo thư viện mbed của DigitalInDigitalOut.
Sau đó thực hiện so sánh ip == 0, chạy hướng dẫn trong {}và sau đó main()kết thúc ... không còn hướng dẫn nào nữa ... Nó làm gì?

Nó có thể thiết lập lại do tìm toán hạng bất hợp pháp trong bộ nhớ flash trống. Hoặc nó sẽ có thể bị treo trong một bộ xử lý lỗi và nháy mắt SOS giống như các xác ướp. Điều này phụ thuộc vào cách thực hiện và có thể vượt xa bạn ngay bây giờ.
Nhưng nếu bạn tò mò, bạn có thể nghiên cứu Xử lý lỗi ARM hoặc tìm ra nơi main()thực sự được gọi từ đâu.

Bây giờ, làm thế nào để khắc phục điều này?

int main() {
    // Add a while(1) infinite loop
    while(1){
        if (ip == 1){
            op = 0;
            wait (1.0);
            op = 1;
        }else{
            op = 1;
        }
    }
    // Program never gets here
}

Cảm ơn bạn rất nhiều vì lời giải thích. Vòng lặp while cho phép nó hoạt động. Thật không may, tôi không thể cho bạn +1 ngay vì đại diện của tôi quá thấp nhưng tôi rất đánh giá cao phản hồi và giải thích
Tò mò

Aha! Câu hỏi thứ ba về câu hỏi của tôi đã cho phép tôi bỏ phiếu trả lời! Cảm ơn một lần nữa
Tò mò

1
@Cquil Nếu bạn muốn điều này rõ ràng hơn với bạn, lập trình viên, bạn có thể viết một cái gì đó giống như while(1 == 1)thay vì chỉ while(1). Cái sau là thành ngữ C, nhưng cái trước rõ ràng hơn với con người vì "sẽ luôn luôn đánh giá là đúng". Bất kỳ trình biên dịch phong nha nào cũng nên tạo cùng một mã nhị phân cho cả hai biến thể.
một CVn

2
@ MichaelKjorling Tôi sẽ không đồng ý với con người rõ ràng hơn. Giống như bộ não của bạn đọc các từ theo hình dạng của chúng thay vì theo ký tự, đối với một lập trình viên có kinh nghiệm, các thành ngữ này dịch trực tiếp sang các khái niệm thay vì diễn giải những gì mỗi câu lệnh riêng lẻ đang làm. Bằng cách di chuyển ra khỏi các cấu trúc thành ngữ, bạn buộc mọi người tham gia với mã của bạn ở mức thấp hơn mức cần thiết để hiểu; mà trên một cơ sở mã lớn thêm vào rất nhiều công việc trí óc không cần thiết.
Chuu

1
@Chuu "bởi một con người [người không phải là lập trình viên có kinh nghiệm]"
user253751

2

Như được đề cập chính xác bởi những người khác, một vòng lặp sẽ cho phép mã của bạn chạy liên tục. Tuy nhiên, có một cách tích hợp để làm điều này cho Arduino mà không cần whilevòng lặp. Điều này được thực hiện bởi loopchức năng - khả năng ứng dụng vào vấn đề của bạn phụ thuộc vào việc bạn có sử dụng Arduino IDE hay không.

Nó sẽ trông giống như thế này:

#include "mbed.h"

DigitalIn ip(D7);
DigitalOut op(D8);

void setup() {
    // any code before loop is run
}

void loop() {
    if (ip == 1){
        op = 0;
        wait (1.0);
        op = 1;
    }else{
        op = 1;
    }
}

Chức năng chính của bạn hiện bị ẩn và chỉ được thêm vào chương trình của bạn khi được biên dịch. Đây là một cuộc thảo luận tốt về điều này: http://forum.arduino.cc/index.php?topic=379368.0


Vâng. Ban đầu tôi đã thực hiện mọi thứ trên một arduino, bao gồm cả điều này vì vậy khi chuyển sang kernel và IDE mbed tôi không thể hiểu tại sao nó không hoạt động!
Tò mò

1
Câu trả lời này dựa vào việc sử dụng hệ thống Arduino. mbed là một hệ thống khác nhau / bộ thư viện và loop()setup()chức năng từ Arduino đang không được sử dụng trong hầu hết các hệ. Để tham khảo, Arduino chỉ đơn giản là định nghĩa một main()cái gì đó như thế này:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Cameron Tacklind

0

Nếu bạn không quen với lắp ráp, điều này có thể là một chút nữa trong vùng thoải mái của bạn:

int chính () {

//A label or function similar to assembly

label:

    if (ip == 1){

        op = 0;

        wait (1.0);

        op = 1;

    }else{

        op = 1;

    }

// Goto used same as "jmp" in assembly

goto label;

// Program never gets here

}


3
Xin vui lòng không sử dụng goto trong bất kỳ ngôn ngữ trên lắp ráp.
Jeroen3

Tôi không quen thuộc gì với lắp ráp Tôi sợ!
Tò mò

Tôi biết về nó nhưng đó là về nó!
Tò mò

@ Jeroen3 Câu hỏi bạn liên kết được trả lời với "goto's phù hợp ở một vài nơi", "Không có gì sai với goto nếu nó được sử dụng đúng cách" và "Không có gì sai với goto trong chính nó". Tôi đồng ý rằng trong các ngôn ngữ có Ngoại lệ, goto là không cần thiết, nhưng đặc biệt là trong C, nó có công dụng của nó.
glglgl

@glglgl: Như Chuu đã đề cập ở trên, mã phải được đọc. goto** mạnh mẽ ** gợi ý "phép thuật đang diễn ra ở đây", có thể ngoại trừ goto cleanup;. Trong ví dụ ở đây, người đọc sẽ bị bỏ lại với câu hỏi khó hiểu "có gì đặc biệt mà bạn không sử dụng while(1) { }ở đây ???".
MSalters
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.