Apa yang menyebabkan program LED mikrokontroler saya berhenti bekerja?

11

Jadi, saya seorang LENGKAP dan pemula di pemrograman. Saya telah melakukan beberapa hal dasar pada Arduinos (secara harfiah mengubah LED dan menampilkan sesuatu pada LCD) dan saya mencoba untuk belajar sendiri tentang cara memprogram dalam C. Saya seorang insinyur perangkat keras berdagang, tetapi itu mengganggu saya bahwa saya tidak bisa lakukan salah satu sisi firmware / perangkat lunak dan tidak ada kursus malam untuk mengajarkannya, dan saya ingin melanjutkan opsi karir saya. Saya berjuang untuk memahami bagaimana beberapa dari perintah ini berjalan bersama dan telah mengalami masalah yang saya tidak bisa mengerti mengapa itu tidak berhasil.

Jadi, saya punya input dan output. Output saya adalah mengaktifkan gerbang FET yang menyalakan LED. Input berasal dari gerbang AND. Jadi, LED saya selalu menyala, dan ketika saya mendapatkan sinyal input dari gerbang AND (2 kondisi telah terpenuhi) Saya ingin output (LED toggle) menjadi RENDAH (matikan LED. Karena output juga terhubung ke salah satu input DAN, ini juga akan mengubah sinyal input RENDAH.

Yang ingin saya lakukan: Saya hanya ingin membaca input sebagai 'kondisi terpenuhi' dan mematikan LED. Kemudian harus dimatikan selama 1 detik, dan hidupkan kembali. Jika input menjadi TINGGI lagi, proses berulang. Saya menggunakan push sederhana untuk beralih sebagai input gerbang AND lainnya dan telah mengukur bahwa output (input MCU) menjadi tinggi ketika tombol ditekan, namun toggle LED (output) tidak akan mati. Kode saya (saya pikir) sangat sederhana, tetapi jelas saya tidak mengerti sesuatu dengan benar karena tidak berfungsi.

Jadi ini kode yang saya gunakan:

#include "mbed.h"

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

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

Dan bagi saya, itu masuk akal. Dalam keadaan biasa, outputnya TINGGI. Jika input mendapatkan sinyal dari gerbang AND, LED akan mati selama 1 detik, lalu nyalakan lagi.

Apa yang saya lakukan salah karena itu terlihat seperti cara logis untuk melakukannya dan saya tidak mengerti mengapa itu tidak berhasil?

Jika itu membantu, saya menggunakan Nucleo F103RB. Ketika saya menggunakan kode 'blink' dan hanya menghidupkan dan mematikan LED seperti itu, itu berfungsi dengan baik, itu hanya ketika saya menambahkan pernyataan 'jika' itu salah.

Ini adalah sirkuit yang disederhanakan:

skema

mensimulasikan rangkaian ini - Skema dibuat menggunakan CircuitLab

PS Saya tahu saya tidak menambahkannya dalam skema, tetapi gerbang DAN memang memiliki resistor pull-down pada input dan output.

Ingin tahu
sumber
Apakah ini berhasil jika Anda memasukkan "ketentuan yang dipenuhi" langsung ke IN?
Transistor
Itu tidak. Saya menekan tombol langsung ke IN dan masih tidak berfungsi
Curious
1
Merupakan ide bagus untuk menandai variabel input sebagai volatile, atau kompiler mungkin melakukan beberapa optimasi aneh dengan mengasumsikan bahwa itu tidak sedang diubah dari luar kode.
Dirk Bruere
3
@DirkBruere: Anda berharap definisi DigitalInsudah termasuk volatile.
MSalters
3
Sekedar petunjuk untuk waktu berikutnya: Coba tahan tombol ketika Anda menghidupkan (atau mengatur ulang) CPU (atau mikrokontroler). Sekarang apa yang terjadi?
CVn

Jawaban:

26

Saya akan berpikir bahwa Anda akan memerlukan loop di sekitar kode Anda -

while(1)
{

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

Sebelum Anda memiliki kesempatan untuk menekan tombol, kode Anda akan selesai dan keluar. Anda perlu waktu untuk menjaga pernyataan if berulang kali berjalan.

HandyHowie
sumber
Apa yang membuat saya berbeda? Saya bisa melihat 'sementara' tetapi apa fungsinya? Permintaan maaf untuk semua pertanyaan tetapi saya benar-benar mulai dengan nol pengetahuan!
Penasaran
1
@Curious Sebelum Anda memiliki kesempatan untuk menekan tombol, kode Anda akan selesai dan keluar. Anda perlu waktu untuk menjaga pernyataan if berulang kali berjalan. Ini biasanya terjadi, kecuali ada sesuatu yang berbeda tentang mikrokontroler yang Anda pemrograman.
HandyHowie
9
"Bisakah Anda menjelaskan mengapa itu berhasil" - Segala sesuatu dalam satu lingkaran sementara diulang sampai kondisinya berubah menjadi nol. Apa kondisinya, Anda mungkin bertanya; itu adalah bagian dalam tanda kurung setelah kata kunci "while" dan seperti yang Anda lihat, kondisinya diatur ke 1, jadi tidak pernah nol dan dengan demikian diulang tanpa batas. Tanpa loop sementara kode dieksekusi hanya sekali dan setelah perangkat lunak berakhir, tetapi dengan loop sementara kode dieksekusi berulang kali hingga Anda menghidupkan perangkat keras.
Jurg
14
Kesalahan Anda mungkin berasal dari pergi ke Arduino ke tempat tidur. Di Arduino Anda biasanya memasukkan kode aplikasi Anda loop(), tetapi kerangka kerja Arduino menambahkan kode yang kira-kira berperilaku seperti itu int main() { setup(); while(1) { loop(); } }.
ris8_allo_zen0
1
@Curious Anda bekerja. Sayangnya itu berjalan tepat sekali, segera ketika Anda dihidupkan. Butuh mungkin satu mikrodetik untuk dijalankan, dan hanya itu. Jika Anda ingin agar tetap memeriksa input dan mengatur output, Anda harus mengatakannya untuk terus melakukannya. "while (some_condition)" berjalan selama "some_condition" benar, yang dalam bahasa C berarti non-nol. Jadi "while (1)" terus memeriksa input selamanya, atau setidaknya selama masih dinyalakan.
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?
}

Prosesor menjalankan instruksi secara berurutan . Dimulai dengan lompatan ke main()dari dalam kode inisialisasi pustaka mbed dari DigitalIndan DigitalOut.
Kemudian lakukan perbandingan ip == 0, jalankan instruksi di dalam {}dan kemudian main()berakhir ... tidak ada instruksi lagi ... Apa fungsinya?

Ini dapat diatur ulang karena menemukan operan ilegal di memori flash kosong. Atau itu bisa menggantung di penangan kesalahan dan berkedip SOS seperti mbeds lakukan. Ini tergantung pada bagaimana ini diterapkan, dan mungkin akan melampaui Anda sekarang.
Tetapi jika Anda penasaran, Anda dapat meneliti ARM Fault Handling, atau mencari tahu dari mana main()sebenarnya namanya.

Sekarang, bagaimana cara memperbaikinya?

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
}
Jeroen3
sumber
Terima kasih banyak atas penjelasannya. Loop sementara memungkinkannya berfungsi. Sayangnya saya belum bisa memberi Anda +1 karena perwakilan saya terlalu rendah, tetapi saya sangat menghargai tanggapan dan penjelasannya
Curious
Aha! Suara positif ketiga atas pertanyaan saya membuat saya memilih jawaban Anda! Terima kasih lagi
Penasaran
1
@Curious Jika Anda ingin ini menjadi lebih jelas bagi Anda, programmer, Anda bisa menulis sesuatu seperti while(1 == 1)bukan hanya while(1). Yang terakhir adalah C idiomatik, tetapi yang pertama lebih jelas bagi manusia karena "akan selalu mengevaluasi ke benar". Setiap kompiler yang layak harus menghasilkan kode biner yang sama untuk kedua varian.
CVn
2
@ MichaelKjörling Saya tidak setuju itu lebih jelas bagi manusia. Sama seperti otak Anda membaca kata-kata berdasarkan bentuknya alih-alih berdasarkan karakter, kepada programmer yang berpengalaman idiom ini menerjemahkan langsung ke konsep daripada menafsirkan apa yang dilakukan setiap pernyataan individu. Dengan beralih dari konstruksi idiomatis Anda memaksa orang untuk terlibat dengan kode Anda tingkat yang lebih rendah dari yang diperlukan untuk pemahaman; yang lebih dari basis kode besar menambah banyak pekerjaan mental yang tidak perlu.
Chuu
1
@Chuu "oleh seorang manusia [yang bukan programmer berpengalaman]"
user253751
2

Seperti yang disebutkan dengan benar oleh orang lain, satu loop akan memungkinkan kode Anda berjalan berulang kali. Namun, ada cara built-in untuk melakukan ini untuk Arduino tanpa perlu whileloop. Ini dilakukan oleh loopfungsi - penerapannya pada masalah Anda tergantung pada apakah Anda menggunakan Arduino IDE.

Seharusnya terlihat seperti ini:

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

Fungsi utama Anda sekarang disembunyikan dan hanya ditambahkan ke program Anda saat dikompilasi. Inilah diskusi yang bagus tentang ini: http://forum.arduino.cc/index.php?topic=379368.0

OLLEY102
sumber
Ya. Saya awalnya melakukan hal-hal pada arduino, termasuk ini jadi ketika beralih ke nukleo dan IDE tempat tidur saya tidak bisa mengerti mengapa itu tidak berhasil!
Penasaran
1
Jawaban ini bergantung pada penggunaan sistem Arduino. mbed adalah sistem / set perpustakaan yang berbeda loop()dan setup()fungsi dari Arduino tidak digunakan di sebagian besar sistem. Untuk referensi, Arduino hanya mendefinisikan main()sesuatu seperti ini:void setup(); void loop(); int main() { setup(); while (true) loop(); }
Cameron Tacklind
0

Jika Anda fimiliar dengan perakitan, ini bisa menjadi sedikit lebih di zona nyaman Anda juga:

int main () {

//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

}

Susmit Agrawal
sumber
3
Tolong jangan gunakan goto dalam bahasa apa pun di atas rakitan.
Jeroen3
Saya sama sekali tidak akrab dengan kebaktian, saya khawatir!
Penasaran
Saya tahu tapi itu saja!
Penasaran
@ Jeroen3 Pertanyaan yang Anda tautkan dijawab dengan "goto tepat di beberapa tempat", "Tidak ada yang salah dengan goto jika digunakan dengan benar" dan "Tidak ada yang salah dengan goto sendiri". Saya setuju bahwa dalam bahasa yang memiliki Pengecualian, goto berlebihan, tetapi khususnya dalam C, ia memiliki kegunaannya.
glglgl
@glglgl: Seperti yang disebutkan Chuu di atas, kode harus dapat dibaca. goto** sangat ** menunjukkan "keajaiban terjadi di sini", mungkin dengan pengecualian goto cleanup;. Dalam contoh di sini, pembaca akan dibiarkan dengan pertanyaan membingungkan "apa yang istimewa yang tidak Anda gunakan di while(1) { }sini ???".
MSalters