Apa alasan kernel RTOS multitasking PIC16 saya tidak berfungsi?


11

Saya mencoba membuat RTOS semi-pre-emptive (koperasi) untuk mikrokontroler PIC x16. Dalam pertanyaan saya sebelumnya , saya telah belajar bahwa mengakses pointer stack perangkat keras tidak dimungkinkan dalam core ini. Saya telah melihat halaman ini di PIClist, dan inilah yang saya coba terapkan dengan menggunakan C.

Kompiler saya adalah Microchip XC8 dan saat ini saya sedang mengerjakan PIC16F616 dengan osilator RC internal 4MHz dipilih dalam bit konfigurasi.

Saya telah belajar bahwa saya dapat mengakses register PCLATH dan PCL dengan C, melihat file header kompiler saya. Jadi, saya mencoba menerapkan pengalih tugas sederhana.

Ini berfungsi seperti yang diinginkan dalam debugger jika saya menjeda debugger setelah restart, reset, dan mengatur PC pada kursor ketika kursor tidak pada baris pertama ( TRISA=0;) tetapi pada baris lain (misalnya ANSEL=0;). Pada awal pertama debugger saya mendapatkan pesan-pesan ini di Debugger Console:

Launching
Programming target
User program running
No source code lines were found at current PC 0x204

Sunting: Saya tidak tahu apa yang membuatnya bekerja, tetapi debugger sekarang berfungsi dengan baik. Jadi, hilangkan output dan paragraf di atas.

Sunting: Mengubah definisi utama seperti ini membuat kode di bawah ini berfungsi. Ini memulai fungsi utama pada alamat program 0x0099. Saya tidak tahu apa penyebabnya. Ini bukan solusi nyata. Saya sekarang menebak bahwa ada kesalahan khusus kompiler.

void main(void) @ 0x0099
{

Ini kode C saya:

/* 
 * File:   main.c
 * Author: abdullah
 *
 * Created on 10 Haziran 2012 Pazar, 14:43
 */
#include <xc.h> // Include the header file needed by the compiler
__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & CP_OFF & IOSCFS_4MHZ & BOREN_ON);
/*
 * INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN
 * WDT disabled and can be enabled by SWDTEN bit of the WDTCON register
 * PWRT enabled
 * MCLR pin function is digital input, MCLR internally tied to VDD
 * Program memory code protection is disabled
 * Internal Oscillator Frequency Select bit : 4MHz
 * Brown-out Reset Selection bits : BOR enabled
 */

/*
 * OS_initializeTask(); definition will copy the PCLATH register to the task's PCLATH holder, which is held in taskx.pch
 * This will help us hold the PCLATH at the point we yield.
 * After that, it will copy the (PCL register + 8) to current task's PCL holder which is held in taskx.pcl.
 * 8 is added to PCL because this line plus the "return" takes 8 instructions.
 * We will set the PCL after these instructions, because
 * we want to be in the point after OS_initializeTask when we come back to this task.
 * After all, the function returns without doing anything more. This will initialize the task's PCLATH and PCL.
 */
#define OS_initializeTask(); currentTask->pch = PCLATH;\
                             currentTask->pcl = PCL + 8;\
                             asm("return");

/*
 * OS_yield(); definition will do the same stuff that OS_initializeTask(); definition do, however
 * it will return to "taskswitcher" label, which is the start of OS_runTasks(); definition.
 */

#define OS_yield();          currentTask->pch = PCLATH;\
                             currentTask->pcl = PCL + 8;\
                             asm("goto _taskswitcher");

/*
 * OS_runTasks(); definition will set the "taskswitcher" label. After that it will change the
 * current task to the next task, by pointing the next item in the linked list of "TCB"s.
 * After that, it will change the PCLATH and PCL registers with the current task's. That will
 * make the program continue the next task from the place it left last time.
 */

#define OS_runTasks();       asm("_taskswitcher");\
                             currentTask = currentTask -> next;\
                             PCLATH = currentTask->pch;\
                             PCL = currentTask->pcl;

typedef struct _TCB // Create task control block and type define it as "TCB"
{
    unsigned char pch; // pch register will hold the PCLATH value of the task after the last yield.
    unsigned char pcl; // pcl register will hold the PCL value of the task after the last yield.
    struct _TCB* next; // This pointer points to the next task. We are creating a linked list.
} TCB;

TCB* currentTask; // This TCB pointer will point to the current task's TCB.

TCB task1; // Define the TCB for task1.
TCB task2; // Define the TCB for task2.

void fTask1(void); // Prototype the function for task1.
void fTask2(void); // Prototype the function for task2.

void main(void)
{
    TRISA = 0; // Set all of the PORTA pins as outputs.
    ANSEL = 0; // Set all of the analog input pins as digital i/o.
    PORTA = 0; // Clear PORTA bits.

    currentTask = &task1; // We will point the currentTask pointer to point the first task.

    task1.next = &task2; // We will create a ringed linked list as follows:
    task2.next = &task1; // task1 -> task2 -> task1 -> task2 ....

    /*
     * Before running the tasks, we should initialize the PCL and PCLATH registers for the tasks.
     * In order to do this, we could have looked up the absolute address with a function pointer.
     * However, it seems like this is not possible with this compiler (or all the x16 PICs?)
     * What this compiler creates is a table of the addresses of the functions and a bunch of GOTOs.
     * This will not let us get the absolute address of the function by doing something like:
     * "currentTask->pcl=low(functionpointer);"
     */
    fTask1(); // Run task1 so that we get the address of it and initialize pch and pcl registers.
    currentTask = currentTask -> next; // Point the currentTask pointer to the next pointer which
    fTask2(); // is task2. And run task2 so that we get the correct pch and pcl.

    OS_runTasks(); // Task switcher. See the comments in the definitions above.
}

void fTask1(void)
{
    OS_initializeTask(); // Initialize the task
    while (1)
    {
        RA0 = ~RA0; // Toggle PORTA.0
        OS_yield(); // Yield
        RA0 = ~RA0; // Toggle PORTA.0
    }
}

void fTask2(void)
{
    OS_initializeTask(); // Initialize the task
    while (1)
    {
        RA1 = ~RA1; // Toggle PORTA.1
        OS_yield(); // Yield
        RA1 = ~RA1; // Toggle PORTA.1
    }
}

Dan di sini adalah file daftar pembongkaran yang dibuat kompiler saya. Mulai dari line 74.

Saya telah memprogram chip yang sebenarnya, dan tidak ada perubahan pada PORTA sama sekali; itu tidak bekerja.

Apa alasan program saya tidak berfungsi?

Jawaban:


10

Apa yang Anda coba lakukan itu rumit, tetapi sangat mendidik (jika Anda siap untuk menghabiskan banyak usaha).

Pertama, Anda harus menyadari bahwa pengalihan tugas PC-only (bukan PC + SP) semacam ini (yang merupakan satu-satunya hal yang dapat Anda lakukan pada inti PIC 12 atau 14-bit yang polos) hanya akan berfungsi ketika semua hasil ( ) pernyataan dalam suatu tugas berada dalam fungsi yang sama: mereka tidak dapat berada dalam fungsi yang disebut, dan kompiler tidak boleh mengacaukan struktur fungsi (seperti yang dilakukan optimasi).

Lanjut:

currentTask->pch = PCLATH;\
currentTask->pcl = PCL + 8;\
asm("goto _taskswitcher");
  • Anda tampaknya menganggap bahwa PCLATH adalah bit atas dari penghitung program, karena PCL adalah bit yang lebih rendah. Ini bukan kasusnya. Ketika Anda menulis ke PCL bit PCLATH ditulis ke PC, tetapi bit PC atas tidak pernah (secara implisit) ditulis ke PCLATH. Baca kembali bagian lembar data yang relevan.
  • Bahkan jika PCLATH adalah bit teratas dari PC, ini akan membuat Anda kesulitan ketika instruksi setelah goto aktif tidak pada 256 halaman 'instruksi' yang sama dengan instruksi pertama.
  • goto polos tidak akan berfungsi ketika _taskswitcher tidak ada di halaman PCLATH saat ini, Anda akan membutuhkan LGOTO atau yang setara.

Solusi untuk masalah PCLATH Anda adalah mendeklarasikan label setelah goto, dan menulis bit bawah dan atas label itu ke lokasi pch dan pcl Anda. Tetapi saya tidak yakin Anda dapat mendeklarasikan label 'lokal' dalam perakitan inline. Anda tentu dapat menggunakan MPASM (Olin akan tersenyum).

Terakhir, untuk pengalihan konteks seperti ini Anda harus menyimpan dan mengembalikan konteks SEMUA yang bergantung pada kompilator, yang mungkin termasuk

  • register tipuan
  • bendera status
  • lokasi memori awal
  • variabel lokal yang mungkin tumpang tindih dalam memori karena kompiler tidak menyadari bahwa tugas Anda harus independen
  • hal-hal lain yang tidak dapat saya bayangkan saat ini tetapi penulis kompiler dapat menggunakan dalam versi berikutnya dari kompiler (mereka cenderung sangat imajinatif)

Arsitektur PIC lebih bermasalah dalam hal ini karena banyak sumber daya yang terhapus di seluruh peta memori, di mana arsitektur yang lebih tradisional memilikinya dalam register atau di stack. Sebagai akibatnya, kompiler PIC sering tidak menghasilkan kode reentrant, yang tentunya Anda perlukan untuk melakukan hal-hal yang Anda inginkan (sekali lagi, Olin mungkin akan tersenyum dan berkumpul bersama.)

Jika Anda menyukai ini karena senang menulis pengalih tugas, saya sarankan Anda menggunakan CPU yang memiliki organisasi yang lebih tradisional, seperti ARM atau Cortex. Jika Anda terjebak dengan kaki di piring beton PIC, pelajari switch PIC yang ada (misalnya salvo / pumkin?).


Terima kasih atas info hebatnya! Saya bertekad untuk membuat pengalih tugas koperasi. XC8 dan PIC tidak berada di pihak saya dalam hal ini, saya menyadari hal itu :) Ya, seperti yang Anda lihat, adalah mungkin untuk membuat label seperti yang saya lakukan di salah satu jawaban saya untuk pertanyaan ini.
abdullah kahraman

Juga, untuk keberuntungan saya, tidak ada paging memori program untuk PIC16F616 yang sedang saya kerjakan, itu adalah keuntungan besar pada saat ini, kan?
abdullah kahraman

Bisakah Anda menjelaskan lebih lanjut bagaimana variabel lokal akan tumpang tindih dalam memori, dan juga "menggaruk lokasi memori"?
abdullah kahraman

Jika Anda membatasi diri pada chip dengan kode 2K atau kurang, Anda memang bisa melupakan lgoto, tetapi tidak tentang 256 halaman 'instruksi'. Scratch: sebuah kompiler dapat mengasumsikan apa pun yang dilakukannya di memori tetap di tempatnya kecuali ia 'volatile'. Jadi mungkin menempatkan perhitungan parsial di beberapa lokasi yang dapat dibagikan oleh fungsi yang berbeda . Ovelap: jika main () memanggil f () dan g () (dan tidak ada panggilan lain), variabel lokal f () dan g () dapat dipetakan ke lokasi memori yang sama.
Wouter van Ooijen

Yah, sepertinya hampir tidak mungkin menjangkau variabel-variabel dan menyimpan, karena tempat acak mereka dalam memori, kan?
abdullah kahraman

7

Saya melihat-lihat daftar perakitan yang Anda berikan, dan tidak ada yang melompat keluar karena jelas rusak.

Jika saya jadi Anda, langkah saya selanjutnya adalah:

(1) Saya akan memilih metode lain untuk mengedipkan LED. "Masalah baca-modifikasi-tulis" yang terkenal dapat (atau mungkin tidak) dipicu oleh "XORWF PORTA, F" dalam daftar perakitan.

Mungkin sesuatu seperti:

// Partial translation of code from abdullah kahraman
// untested code
// feel free to use however you see fit
void fTask2(void)
{
    OS_initializeTask(2); // Initialize task 2
    while (1)
    {
        PORTC = 0xAA;
        OS_yield(2); // Yield from task 2
        PORTC = 0x55;
        OS_yield(2); // Yield from task 2
    }
}

(Jika Anda benar-benar ingin melihat penjelasan terperinci tentang mengapa "XORWF PORTA, F" sering menyebabkan masalah, lihat " Apa yang menyebabkan menyalakan pin output tunggal pada Microchip PIC16F690 untuk secara spontan mematikan pin lain pada port yang sama? "; " Apa yang terjadi ketika data ditulis ke LATCH? ";" Masalah Read-Modify-Write ";" Read before Write ")

(2) Saya akan langkah-tunggal melalui kode, memastikan bahwa variabel sedang diatur ke nilai yang diharapkan dan dalam urutan yang diharapkan. Saya tidak yakin apakah ada hardware debugger satu langkah untuk PIC16F616, tetapi ada banyak simulator mikrokontroler PIC yang sangat baik seperti PICsim yang dapat mensimulasikan chip seri PIC16.

Kode langkah-tunggal (dalam simulator atau dengan perangkat keras langkah-tunggal) adalah cara yang baik untuk memahami detail tentang apa yang sebenarnya terjadi, mengonfirmasi bahwa segala sesuatu terjadi seperti yang Anda inginkan, dan memungkinkan Anda melihat hal-hal yang hampir mustahil untuk melihat ketika menjalankan program dengan kecepatan penuh.

(3) Jika saya masih bingung, saya akan mencoba menerjemahkan kode untuk menggunakan array daripada pointer. Beberapa orang merasa menggunakan pointer agak rumit dan sulit untuk di-debug. Saya sering menemukan bahwa, dalam proses menerjemahkan kode penunjuk rumit ke dalam kode berorientasi array, saya mencari tahu apa bug itu. Bahkan jika saya akhirnya kembali ke kode pointer asli dan membuang versi array, latihan ini berguna karena membantu saya menemukan dan memperbaiki bug. (Terkadang kompiler dapat menghasilkan kode lebih pendek, lebih cepat dari kode berorientasi array, jadi ada kalanya saya membuang kode pointer asli dan menyimpan versi array).

Mungkin seperti itu

// Partial translation of code from abdullah kahraman
// untested code
// feel free to use however you see fit
struct TCB_t // Create task control block and type define it as "TCB_t"
{
    unsigned char pch; // PCLATH value
    unsigned char pcl; // PCL value
    int next; // This array index points to the next task. We are creating a linked list.
};

int currentTask = 1; // This TCB index will point to the current task's TCB.

struct TCB_t tasks[3]; // Define the TCB for task1 and task2.

#define OS_initializeTask(x); tasks[x].pch = PCLATH;\
                             tasks[x].pcl = PCL + 8;\
                             asm("return");

#define OS_runTasks();       asm("_taskswitcher");\
                             currentTask = tasks[currentTask].next;\
                             PCLATH = tasks[currentTask].pch;\
                             PCL = tasks[currentTask].pcl;

#define OS_yield(x);         tasks[x].pch = PCLATH;\
                             tasks[x].pcl = PCL + 8;\
                             asm("goto _taskswitcher");

Saya mengimplementasikan array sekarang. Terima kasih untuk rekomendasinya.
abdullah kahraman

3

Saya pada dasarnya akan setuju dengan davidcary. Sepertinya itu bisa berhasil.

Saya tidak tahu apa yang membuatnya bekerja, tetapi debugger sekarang berfungsi dengan baik.

Saya menduga maksud Anda ini berfungsi dengan baik di simulator .

1) Periksa apakah tugas Anda bekerja sendiri, dalam lingkungan non-RTOS dalam chip nyata.

2) Melakukan debugging dalam-sirkuit. Langkah melalui program pada chip nyata, dan menonton semua variabel yang relevan untuk memastikan bahwa semuanya berjalan sesuai rencana.


Ya, saya maksudkan debugger, itu adalah simulator MPLABX. Tugas bekerja sendiri, di lingkungan non-RTOS. Saya tidak punya ICD. Saya hanya punya mikroElektronika easyPIC5 dengan ICD, namun hanya berfungsi dengan kompiler mikroC. Sekarang, mengganti kompiler tidak akan membiarkan saya menemukan masalah, atau, bukan?
abdullah kahraman

1

Saya hanya melihat kode Anda sebentar, tetapi tidak masuk akal. Di beberapa tempat Anda menulis ke PCL, kemudian mengharapkannya untuk mengeluarkan instruksi lain setelah itu.

Seperti yang saya katakan sebelumnya, C tidak sesuai untuk jenis akses rendah register perangkat keras mendasar. Anda benar-benar perlu menggunakan perakitan untuk ini. Mencoba mencari tahu mengapa kode C tidak berfungsi hanya buang-buang waktu saja.


Saya tidak dapat menggabungkan perakitan dan C. Saya harus melakukan banyak pekerjaan. Baik kode dis-assembly dan C tampak logis bagi saya. Di mana Anda merujuk bahwa saya mengharapkan untuk melaksanakan instruksi yang mengikuti penulisan ke PCL? Saya telah menyaksikan debugger untuk assembly dan C, dan berfungsi seperti yang diharapkan.
abdullah kahraman

Maaf untuk -1. Saya seharusnya menekan secara tidak sengaja dan saya memerhatikan itu sekarang.
abdullah kahraman

@ abdullah: Di mesin saya sekarang, saya tidak bisa melihat kode sumber. Itu secara permanen diciutkan di browser. Saya ingat bahwa Anda menetapkan hal-hal untuk PCLATH, lalu PCL, maka saya pikir dalam satu kasus mencoba untuk melakukan PENGEMBALIAN. Segera setelah Anda menulis ke PCL, eksekusi akan melompat ke alamat yang Anda masukkan ke PCLATH: PCL, jadi semua instruksi berikut ini tidak relevan. Ini benar-benar tidak baik untuk melakukan ini di C karena Anda mengacaukan sumber daya yang dikelola kompiler dan dengan demikian mungkin membatalkan asumsi kompiler. Sudah gunakan perakitan asli. Aku bosan harus mengulang ini.
Olin Lathrop

1
Melihat kode tersebut, tidak ada tempat di mana PCL dimodifikasi sebelum pernyataan lain. Satu-satunya tempat yang tampaknya dimodifikasi adalah di bagian paling akhir main (). Tapi itu poin yang bagus bahwa Anda harus sangat yakin Anda tidak memperjuangkan kompiler untuk sumber dayanya. Anda berdua akan kalah.
Rocketmagnet

3
C sangat dapat diterima untuk jenis pekerjaan ini, dan sebenarnya lebih baik menulis dalam bahasa tingkat menengah seperti C sebagai lawan dari bahasa assembly karena lebih mudah dibaca dan dipelihara. Kompiler yang layak akan menghasilkan kode tidak jauh dari apa yang rata-rata orang akan tulis. Saya biasanya hanya menulis assembler untuk kode startup yang sangat dasar, area spesifik tempat saya dapat mengoptimalkan lebih baik daripada kompiler atau untuk interupsi cepat, atau jika batasan ukuran kode mendikte itu. Tidak banyak kebutuhan untuk perakitan murni hari ini.
akohlsmith

1

Di bawah ini adalah cara untuk melakukannya dengan perakitan in-line menggunakan kompiler XC8, dan berfungsi sekarang! Namun, saya perlu menambahkan mengembangkan lebih banyak kode untuk menyimpan dan mengembalikan STATUSregister, yang tampaknya sedikit rumit daripada register normal.

Sunting: Kode diubah. Silakan merujuk ke versi yang lebih lama dari posting ini untuk kode sebelumnya.

/*
 * File:   main.c
 * Author: abdullah
 *
 * Created on 10 Haziran 2012 Pazar, 14:43
 */
#include <xc.h> // Include the header file needed by the compiler
#include "RTOS.h" // Include the header for co-operative RTOS.
__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & CP_OFF & IOSCFS_4MHZ & BOREN_ON);

unsigned char OS_currentTask; // This register holds the current task's place in the array OS_tasks
unsigned char OS_tasks[4]; // This array holds PCL and PCLATH for tasks. This array will have..
//                            .. (number of tasks)*2 elements, since every task occupies 2 places.

void fTask1(void); // Prototype the function for task1.
void fTask2(void); // Prototype the function for task2.

void main(void)
{
    TRISA = 0; // Set all of the PORTA pins as outputs.
    TRISC = 0; // Set all of the PORTC pins as outputs.
    ANSEL = 0; // Set all of the analog input pins as digital i/o.
    PORTA = 0; // Clear PORTA bits.
    PORTC = 0; // Clear PORTC bits.

    OS_currentTask = 0; // Current task is first task.
    fTask1(); // Call task to initialize it.
    OS_currentTask += 2; // Increment task pointer by two since every task occupies 2 places in the array.
    fTask2(); // Call task to initialize it.
    OS_runTasks(4); // Run the tasks in order. The argument of this macro takes is: (Number of tasks) * 2
}

void fTask1(void)
{
    OS_initializeTask(); // Initialize the task so that task runner can get its ingredients.
    while (1)
    {
        PORTC = 0xAA;
        OS_yield(); // Yield CPU to other tasks.
        PORTC = 0x55;
        OS_yield(); // Yield CPU to other tasks.
    }
}

void fTask2(void)
{
    OS_initializeTask(); // Initialize the task so that task runner can get its ingredients.
    while (1)
    {
        PORTC = 0xFF;
        OS_yield(); // Yield CPU to other tasks.
        PORTC = 0x00;
        OS_yield(); // Yield CPU to other tasks.
    }
}

Dan di sini adalah file tajuk RTOS.h:

/* 
 * File:   RTOS.h
 * Author: abdullah
 *
 * Created on 21 Haziran 2012 Perşembe, 10:51
 */

#ifndef RTOS_H
#define RTOS_H

asm("OS_yield MACRO");
asm("local OS_tmp");
asm("movlw   _OS_tasks            ; Store the address of tasks, which is the start address of our task 'array'."); 
asm("addwf   _OS_currentTask, w   ; Add current task's index to the start address."); 
asm("movwf   fsr                  ; We have the index of current task in W. Copy it to FSR"); 
asm("movlw   high(OS_tmp)         ; Copy PCLATH register's contents for the label, to W register.");
asm("movwf   indf                 ; Copy W to current task's first item. We now store PCLATH of the current state of the task."); 
asm("incf    fsr, f               ; Increment index, so that we will point to the next item of current task."); 
asm("movlw   low(OS_tmp)          ; Copy PCL of the label to W register. This will let us save the PCL of the current state of the task.");
asm("movwf   indf                 ; Copy W to task's next item. With that, we will initialize the current task.");
asm("goto    OS_taskswitcher");
asm("OS_tmp:                      ; We will use this label to gather the PC of the return point.");
asm("ENDM"); 

#define OS_yield(); asm("OS_yield");

asm("OS_initializeTask MACRO");
asm("local   OS_tmp");
asm("movlw   _OS_tasks            ; Store the address of tasks, which is the start address of our task 'array'."); 
asm("addwf   _OS_currentTask, w   ; Add current task's index to the start address."); 
asm("movwf   fsr                  ; We have the index of current task in W. Copy it to FSR"); 
asm("movlw   high(OS_tmp)        ; Copy PCLATH register's contents for the label, to W register."); 
asm("movwf   indf                 ; Copy W to current task's first item. We now store PCLATH."); 
asm("incf    fsr,f                ; Increment index, so that we will point to the next item of current task."); 
asm("movlw   low(OS_tmp)         ; Copy PCL of the label to W register. This will let us save the PCL of the current state of the task."); 
asm("movwf   indf                 ; Copy W to task's next item. With that, we will initialize the current task."); 
asm("return                       ; We have gathered our initialazation information. Return back to main."); 
asm("OS_tmp                      ; We will use this label to gather the PC of the return point.");
asm("ENDM"); 

#define OS_initializeTask(); asm("OS_initializeTask");

asm("OS_runTasks MACRO numberOfTasks");
asm("global OS_taskswitcher");
asm("OS_taskswitcher:");
asm("CLRWDT"); 
asm("movlw   0x02                 ; W = 2"); 
asm("addwf   _OS_currentTask, f   ; Add 2 to currentTask, store it in currentTask."); 
asm("movlw   numberOfTasks        ; W = numOfTasks");
asm("subwf   _OS_currentTask, w   ; w= f - w"); 
asm("btfsc   status, 0            ; If currentTask >= numOfTasks"); 
asm("clrf    _OS_currentTask      ; Clear currentTask"); 
asm("movlw   _OS_tasks            ; Store the address of tasks, which is the start address of our task 'array'."); 
asm("addwf   _OS_currentTask, w   ; Add current task's index to the start address."); 
asm("movwf   fsr                  ; We have the index of current task in W. Copy it to FSR"); 
asm("movf    indf, w              ; Copy the contents of current task's first item to W"); 
asm("movwf   pclath               ; Copy W to PCLATH. As a result, current task's PCLATH will be in PCLATH register."); 
asm("incf    fsr, f               ; Increment index, so that we will point to the next item of current task."); 
asm("movf    indf, w              ; Copy the contents of current task's second item to W."); 
asm("movwf   pcl                  ; Copy W to PCL. Finally, current task's PCL will be in PCL register.");
asm("ENDM");

#define OS_runTasks(numberOfTasks); asm("OS_runTasks "#numberOfTasks);

#endif  /* RTOS_H */

Sepertinya Anda akan memenangkan hadiah Anda sendiri. Selamat! :-)
stevenvh

@stevenvh Ah, apakah itu terjadi, saya tidak tahu? Terima kasih :)
abdullah kahraman

Selamat untuk membuatnya bekerja!
davidcary

Terima kasih @davidcary! Saya sangat menghargai ucapan selamat kalian semua.
abdullah kahraman

1
Apakah Anda benar-benar perlu memulihkan STATUS? Jika demikian, Anda harus menggunakan instruksi "swapf", untuk alasan yang didokumentasikan di tempat lain: " P. Anderson ", " Microchip Mid-range manual keluarga: bagian 8.5 Penghematan Konteks ", " Penghematan PIC W dan STATUS "
davidcary

0

Di bawah ini adalah cara mengimplementasikan perakitan menggunakan ini. Akses kode yang sama dengan pemformatan (tautan ke Pastebin) . Bagaimana itu bisa diperbaiki? Ini adalah program pertama saya di perakitan PIC, ada komentar yang dihargai.

list p=16f616
#include p16f616.inc

;*** Configuration Bits ***
__CONFIG _FOSC_INTOSCIO & _WDTE_OFF & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _IOSCFS_8MHZ & _BOREN_ON
;**************************

;*** Variable Definitions ***
VARS        UDATA                   ; Define undefined data(s).
numOfTasks  res     1               ; This variable holds the number of tasks multiplied by 2.
currentTask res     1               ; Index variable that points to the current task's index in "tasks"
tasks       res     4               ; This is task "array". Every task occupies 2 bytes.
;****************************

;*** Reset Vector ***
RESET   CODE    0x0000              ; Define a code block starting at 0x0000, which is reset vector, labeled "RESET"
        goto    start               ; Start the program.
;********************

;*** Main Code ***
MAIN    CODE
start                               ; Label the start of the program as "start".
        banksel TRISA               ; Select appropriate bank for TRISA.
        clrf    TRISA               ; Clear TRISA register. Configure all of the PORTA pins as digital outputs.
        clrf    TRISC               ; Clear TRISC register. TRISC and TRISA are at the same bank, no need for "banksel".
        clrf    ANSEL               ; Clear ANSEL register and configure all the analog pins as digital i/o.
        banksel PORTA               ; Select appropriate bank for PORTA.
        clrf    PORTA               ; Clear PORTA register.
        clrf    PORTC               ; Clear PORTC register. PORTC and PORTA are at the same bank, no need for "banksel".


        movlw   0x04                ; W = Number of tasks * 2.
        movwf   numOfTasks          ; Since every task has two datas in it, we will multiply by 2.
        clrf    currentTask         ; Set the task#0 as current task.

        CALL    task0               ; Call task#0 since we need to initialize it. We are going to get..
                                    ; ..its PCL and PCLATH values at the start address.
        movlw   0x02                ; W = 2
        addwf   currentTask, f      ; Increment currentTask by 2, since every task occupies 2 places.

        CALL    task1               ; Call task#1, for initialazation.

taskswitcher
        movlw   0x02                ; W = 2
        addwf   currentTask, f      ; Add 2 to currentTask, store it in currentTask.
        movf    numOfTasks, w       ; W = numOfTasks
        subwf   currentTask, w      ; w= f - w
        btfsc   STATUS, 0           ; If currentTask >= numOfTasks
        clrf    currentTask         ; Clear currentTask

        movlw   tasks               ; Store the address of tasks, which is the start address of our task "array".
        addwf   currentTask, w      ; Add current task's index to the start address.
                                    ; For example; task1's index is 2:  [task0_1][task0_2][task1_1][task1_2]....
                                    ;                                       0        1        2        3
        movwf   FSR                 ; We have the index of current task in W. Copy it to FSR
        movf    INDF, w             ; Copy the contents of current task's first item to W
        movwf   PCLATH              ; Copy W to PCLATH. As a result, current task's PCLATH will be in PCLATH register.

        incf    FSR, f              ; Increment index, so that we will point to the next item of current task.
        movf    INDF, w             ; Copy the contents of current task's second item to W.
        movwf   PCL                 ; Copy W to PCL. Finally, current task's PCL will be in PCL register.

        goto    $                   ; This instruction is not effective. But, enter the endless loop.

;*** TASK 0 ***
TASK0   CODE
;**************
task0
        movlw   tasks               ; Store the address of tasks, which is the start address of our task "array".
        addwf   currentTask, w      ; Add current task's index to the start address.

        movwf   FSR                 ; We have the index of current task in W. Copy it to FSR
        movf    PCLATH, w           ; Copy PCLATH register's contents to W register.
        movwf   INDF                ; Copy W to current task's first item. We now store PCLATH.

        incf    FSR,f               ; Increment index, so that we will point to the next item of current task.
        movlw   low($+3)            ; Copy PCL+3 to W register. This will let us save the PCL of the start of the task.
        movwf   INDF                ; Copy W to task's next item. With that, we will initialize the current task.
        return                      ; We have gathered our initialazation information. Return back to main.

task0main
        banksel PORTA               ; Select the appropriate bank for PORTA
        movlw   0xAA                ; Move literal to W so that W = 0xAA
        movwf   PORTA               ; PORTA = 0xAA. Use a LATA register to create more robust code.

        movlw   tasks               ; Store the address of tasks, which is the start address of our task "array".
        addwf   currentTask, w      ; Add current task's index to the start address.

        movwf   FSR                 ; We have the index of current task in W. Copy it to FSR
        movf    PCLATH, w           ; Copy PCLATH register's contents to W register.
        movwf   INDF                ; Copy W to current task's first item. We now store PCLATH of the current state of the task.

        incf    FSR,f               ; Increment index, so that we will point to the next item of current task.
        movlw   low($+3)            ; Copy PCL+3 to W register. This will let us save the PCL of the current state of the task.
        movwf   INDF                ; Copy W to task's next item. With that, we will initialize the current task.

        goto    taskswitcher        ; Yield the CPU to the awaiting task by going to task switcher.

        banksel PORTA               ; Select the appropriate bank for PORTA
        movlw   0x55                ; Move literal to W so that W = 0x55
        movwf   PORTA               ; PORTA = 0xAA. Use a LATA register to create more robust code.

        goto    task0main           ; Loop by going back to "task0main". We will continuously toggle PORTA.

;*** TASK 1 ***
TASK1   CODE
;**************
task1
        movlw   tasks               ; Store the address of tasks, which is the start address of our task "array".
        addwf   currentTask, w      ; Add current task's index to the start address.

        movwf   FSR                 ; We have the index of current task in W. Copy it to FSR
        movf    PCLATH, w           ; Copy PCLATH register's contents to W register.
        movwf   INDF                ; Copy W to current task's first item. We now store PCLATH.

        incf    FSR,f               ; Increment index, so that we will point to the next item of current task.
        movlw   low($+3)            ; Copy PCL+3 to W register. This will let us save the PCL of the start of the task.
        movwf   INDF                ; Copy W to task's next item. With that, we will initialize the current task.
        return                      ; We have gathered our initialazation information. Return back to main.

task1main
        banksel PORTA               ; Select the appropriate bank for PORTA
        movlw   0xAA                ; Move literal to W so that W = 0xAA
        movwf   PORTA               ; PORTA = 0xAA. Use a LATA register to create more robust code.

        movlw   tasks               ; Store the address of tasks, which is the start address of our task "array".
        addwf   currentTask, w      ; Add current task's index to the start address.

        movwf   FSR                 ; We have the index of current task in W. Copy it to FSR
        movf    PCLATH, w           ; Copy PCLATH register's contents to W register.
        movwf   INDF                ; Copy W to current task's first item. We now store PCLATH of the current state of the task.

        incf    FSR,f               ; Increment index, so that we will point to the next item of current task.
        movlw   low($+3)            ; Copy PCL+3 to W register. This will let us save the PCL of the current state of the task.
        movwf   INDF                ; Copy W to task's next item. With that, we will initialize the current task.

        goto    taskswitcher        ; Yield the CPU to the awaiting task by going to task switcher.

        banksel PORTA               ; Select the appropriate bank for PORTA
        movlw   0x55                ; Move literal to W so that W = 0x55
        movwf   PORTA               ; PORTA = 0xAA. Use a LATA register to create more robust code.

        goto    task1main           ; Loop by going back to "task1main". We will continuously toggle PORTA.

        END                         ; END of the program.

Program pertama Anda dalam perakitan adalah RTOS multi-tasking? Wow. Kebanyakan orang melakukan sangat baik jika mereka bisa mendapatkan LED untuk berkedip. :-).
davidcary

Sebenarnya ini adalah program perakitan pertama saya dalam arsitektur PIC . Sebelum itu, di universitas, saya telah mengambil 8086 kelas tetapi mereka tidak praktis dan saya harus belajar sendiri karena dosen adalah pengganti dan tidak tahu apa-apa, belum mengajukan pertanyaan sulit dalam ujian ..
abdullah kahraman
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.