PIC16 çoklu görev RTOS çekirdeğimin çalışmamasının nedeni nedir?


11

PIC x16 mikrodenetleyicileri için yarı önleyici (kooperatif) bir RTOS oluşturmaya çalışıyorum. Benim içinde önceki soruya, ben donanım yığın işaretçisi erişen bu çekirdeklerinde mümkün olmadığını öğrendik. PIClist'teki bu sayfaya baktım ve C kullanarak uygulamaya çalışıyorum.

Derleyicim Microchip XC8 ve şu anda yapılandırma bitlerinde 4MHz dahili RC osilatörü seçilmiş bir PIC16F616 üzerinde çalışıyorum.

Derleyicimin başlık dosyasına bakarak C ile PCLATH ve PCL kayıtlarına erişebildiğimi öğrendim. Bu yüzden basit bir görev değiştirici uygulamaya çalıştım.

İmleç ilk satırda ( TRISA=0;) değil, başka bir satırda (örneğin ANSEL=0;) PC'yi imleci yeniden başlattıktan, sıfırladıktan ve ayarladıktan sonra hata ayıklayıcıyı duraklatırsam hata ayıklayıcıda istendiği gibi çalışır . Hata ayıklayıcının ilk başlangıcında şu iletileri alıyorum Debugger Console:

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

Düzenleme: Ne işe yaradığını bilmiyorum, ama hata ayıklayıcı şimdi mükemmel çalışıyor. Bu nedenle, yukarıdaki çıktıyı ve paragrafı atlayın.

Düzenleme: Ana tanımın bu şekilde değiştirilmesi aşağıdaki kodun çalışmasını sağlar. Bu, ana işlevi program adresinde başlatır 0x0099. Buna neyin sebep olduğunu bilmiyorum. Bu gerçek bir çözüm değil. Şimdi derleyiciye özgü bir hata olduğunu tahmin ediyorum.

void main(void) @ 0x0099
{

İşte benim C kodu:

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

Ve burada benim derleyici yarattı sökme listeleme dosyasıdır. Konumunda başlar line 74.

Gerçek çipi programladım ve PORTA'da hiç değişiklik yok; çalışmıyor.

Programımın çalışmamasının nedeni nedir?

Yanıtlar:


10

Yapmaya çalıştığınız şey zor, ama çok eğitici (eğer çok çaba sarf etmeye hazırsanız).

İlk olarak, bu tür PC'lerin (PC + SP'nin aksine) görev değiştirmenin (düz 12 veya 14 bit PIC çekirdeğinde yapabileceğiniz tek şey) sadece tüm verim ( ) bir görevdeki ifadeler aynı işleve sahiptir: çağrılan bir işlevde olamazlar ve derleyici işlev yapısına zarar vermemelidir (optimizasyon gibi).

Sonraki:

currentTask->pch = PCLATH;\
currentTask->pcl = PCL + 8;\
asm("goto _taskswitcher");
  • PCLATH'ın program sayacının üst bitleri olduğunu varsayıyorsunuz, çünkü PCL alt bitler. Olay bu değil. PCL'ye yazdığınızda PCLATH bitleri PC'ye yazılır, ancak üst PC bitleri asla (örtük olarak) PCLATH'a yazılmaz. Veri sayfasının ilgili bölümünü yeniden okuyun.
  • PCLATH PC'nin üst bitleri olsa bile, goto'dan sonraki talimat ilk talimatla aynı 256 talimatlı 'sayfada' olmadığında bu sizi rahatsız eder.
  • _taskswitcher geçerli PCLATH sayfasında olmadığında düz goto çalışmaz, bir LGOTO veya eşdeğeri gerekir.

PCLATH sorununuza bir çözüm, goto'dan sonra bir etiket bildirmek ve bu etiketin alt ve üst bitlerini pch ve pcl konumlarınıza yazmaktır. Ancak satıriçi montajda 'yerel' bir etiket beyan edebileceğinizden emin değilim. Düz MPASM (Olin gülümseyecek) emin olabilirsiniz.

Son olarak, bu tür bir bağlam değiştirme için, derleyicinin bağlı olabileceği TÜM içeriği kaydetmeli ve geri yüklemelisiniz;

  • dolaylı kayıtlar
  • durum bayrakları
  • sıfırdan bellek konumları
  • derleyici görevlerinizin bağımsız olması gerektiğini fark etmediği için bellekte çakışabilecek yerel değişkenler
  • şu anda hayal edemediğim diğer şeyler ancak derleyici yazarı derleyicinin bir sonraki sürümünde kullanabilir (çok yaratıcı olma eğilimindedir)

PIC mimarisi bu açıdan daha sorunludur, çünkü bellek haritasının her yerinde çok sayıda kaynak bulunur, burada daha geleneksel mimarlar onları kayıtlarda veya yığınta bulundurur. Sonuç olarak, PIC derleyicileri genellikle yeniden kodlama kodu üretmez, bu da istediğiniz şeyleri yapmak için kesinlikle ihtiyacınız olan şeydir (yine Olin muhtemelen gülümseyecek ve bir araya gelecek.)

Bir görev değiştirici yazma sevinci için bunu yapıyorsanız, ARM veya Cortex gibi daha geleneksel bir organizasyona sahip bir CPU'ya geçmenizi öneririm. Ayaklarınızla PIC'lerin beton bir tabağında sıkışırsanız, mevcut PIC anahtarlayıcılarını inceleyin (örneğin salvo / balkabağı?).


Harika bilgi için teşekkürler! Bir kooperatif görev değiştirici oluşturmaya kararlıyım. XC8 ve PIC bu konuda yanımda değil, bunun farkındayım :) Evet, gördüğünüz gibi, bu soruya verdiğim cevaplardan birinde yaptığım gibi etiketler oluşturmak mümkündür .
abdullah kahraman

Ayrıca, şansıma, üzerinde çalıştığım PIC16F616 için program belleğinde disk belleği yok, bu noktada büyük bir avantaj, değil mi?
abdullah kahraman

Yerel değişkenlerin bellekte nasıl üst üste bineceğini ve ayrıca "bellek konumlarını kazımayı" açıklayabilir misiniz?
abdullah kahraman

Kendinizi 2K veya daha az kodlu yongalarla kısıtlarsanız, lgoto'yu gerçekten unutabilirsiniz, ancak 256 talimatlı 'sayfalar'ı unutamazsınız. Scratch: Bir derleyici, 'uçucu' olmadıkça bellekte yaptığı her şeyin yerinde olduğunu varsayabilir. Bu nedenle , farklı işlevler tarafından paylaşılabilecek bir yere kısmi hesaplamalar koyabilir . Ovelap: main () hem f () hem de g () 'yi çağırıyorsa (ve başka çağrı yoksa), f () ve g ()' nin yerel değişkenleri aynı bellek konumlarıyla eşlenebilir.
Wouter van Ooijen

Peki, bu değişkenlere ulaşmak ve hafızadaki rastgele yerlerinden dolayı depolamak neredeyse imkansız gibi görünüyor, değil mi?
abdullah kahraman

7

Sağladığınız montaj listesine göz attım ve hiçbir şey açıkça kırılmadı.

Ben senin yerinde olsaydım, bir sonraki adım:

(1) LED'leri yanıp sönmenin başka bir yöntemini seçerdim. Kötü amaçlı "okuma-değiştirme-yazma sorunu", montaj listesindeki "XORWF PORTA, F" tarafından tetiklenebilir (veya olmayabilir).

Belki şöyle bir şey:

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

("XORWF PORTA, F" nin neden genellikle sorunlara neden olduğu hakkında ayrıntılı açıklamalar görmek istiyorsanız, bkz. " Microchip PIC16F690'da tek bir çıkış piminin AÇIK konuma getirilmesine ne neden olur? "; " Ne olur ? "; veriler LATCH'a yazıldığında? ";" Okuma-Değiştirme-Yazma sorunu ";" Yazmadan Önce Oku ")

(2) Değişkenlerin beklenen değerlere ve beklenen sırayla ayarlandığından emin olarak kod boyunca tek adımda ilerlerim. PIC16F616 için tek adımlı bir donanım hata ayıklayıcı olup olmadığından emin değilim, ancak PIC16 serisi yongaları simüle edebilen PICsim gibi birçok mükemmel PIC mikrodenetleyici simülatörü var .

Tek adımlık kod (bir simülatörde veya tek adımlı bir donanım hata ayıklayıcıda), gerçekten neler olup bittiğinin ayrıntılarını anlamanın, işlerin istediğiniz gibi gerçekleştiğini doğrulamanın iyi bir yoludur ve programı tam hızlı çalıştırırken görmek neredeyse imkansız.

(3) Eğer hala güdük, işaretçiler yerine dizileri kullanmak için kodu çevirmek çalışacağım. Bazı insanlar işaretçiler kullanmak biraz zor ve hata ayıklamak zor bulur. Sık sık, zor işaretçi kodunu dizi odaklı koda çevirme sürecinde , hatanın ne olduğunu buluyorum. Orijinal işaretçi koduna geri dönüp dizi sürümünü atmamda bile, egzersiz yararlıdır çünkü hatayı bulup düzeltmeme yardımcı oldu. (Bazen derleyici diziye yönelik koddan daha kısa, daha hızlı kod üretebilir, bu yüzden orijinal işaretçi kodunu atıp dizi sürümünü sakladığım zamanlar vardır).

Belki de

// 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");

Şimdi diziler uyguluyorum. Tavsiye için teşekkürler.
abdullah kahraman

3

Davidcary ile hemfikirim. İşe yarayabilecek gibi görünüyor.

Neyin işe yaradığını bilmiyorum, ancak hata ayıklayıcı şimdi mükemmel çalışıyor.

Bunu tahmin ediyorum, simülatörde mükemmel çalıştığını söylüyorsunuz .

1) Görevlerinizin gerçek çipte RTOS olmayan bir ortamda kendi başlarına çalışıp çalışmadığını kontrol edin.

2) Devre içi hata ayıklama yapın. Gerçek çip üzerinde programa adım atın ve her şeyin planlandığı gibi gittiğinden emin olmak için tüm ilgili değişkenleri izleyin.


Evet, hata ayıklayıcıyı kastediyorum, bu MPLABX'in simülatörü. Görevler RTOS olmayan bir ortamda kendi başlarına çalışır. ICD'm yok. ICD ile sadece mikroElektronika easyPIC5 var, ancak sadece mikroC derleyici ile çalışır. Şimdi, derleyicileri değiştirmek sorunu bulmama izin vermiyor, yoksa değil mi?
abdullah kahraman

1

Kodunuza sadece kısaca baktım, ama mantıklı değil. Birkaç yerde PCL'ye yazıyorsunuz ve daha sonra diğer talimatları izlemesini bekliyorsunuz.

Daha önce de söylediğim gibi, C temel donanım kayıtlarına bu tür düşük seviyeli erişim için uygun değildir. Bunun için gerçekten montaj kullanmanız gerekiyor. C kodunun neden çalışmadığını anlamaya çalışmak sadece anlamsız bir zaman kaybıdır.


Montaj ve C'yi birleştiremedim. Çok fazla iş yapmak zorunda kaldım. Hem sökme hem de C kodu bana mantıklı geliyor. PCL'ye yazmayı izleyen talimatları yürütmeyi beklediğimi nereden söylüyorsunuz? Hata ayıklayıcıyı hem montaj hem de C için izledim ve istendiği gibi çalışıyor.
abdullah kahraman

-1 için üzgünüm. Yanlışlıkla baskı yapmalıydım ve şimdi fark ettim.
abdullah kahraman

@abdullah: Şu anda makinede, kaynak kodunu göremiyorum. Tarayıcıda kalıcı olarak daraltılır. PCLATH'a, sonra PCL'ye bir şeyler atadığınızı hatırlıyorum, o zaman bir durumda İADE yapmaya çalıştığımı düşünüyorum. PCL'ye yazdığınızda, uygulama PCLATH: PCL'ye doldurduğunuz adrese atlayacaktır, bu nedenle aşağıdaki talimatlar önemsizdir. Derleyici yönetilen kaynaklarla uğraştığınız ve dolayısıyla derleyici varsayımlarını geçersiz kıldığınız için bunu C'de yapmak gerçekten iyi değil . Gerçek montajı zaten kullanın. Bunu tekrarlamaktan yoruldum.
Olin Lathrop

1
Koda bakıldığında, PCL'nin başka bir ifadeden hemen önce değiştirildiği hiçbir yer yoktur. Değiştirilmiş gibi görünen tek yer main () 'nin sonudur. Ancak derleyici kaynakları için savaşmadığınızdan emin olmanız iyi bir nokta. Ofkiniz de kaybedeceksiniz.
Rocketmagnet

3
C bu tür işler için mükemmel bir şekilde kabul edilebilir ve aslında montaj dilinin aksine C gibi orta seviye bir dilde yazmak tercih edilir, çünkü okunması ve bakımı daha kolaydır. İyi bir derleyici, ortalama bir kişinin ne yazacağından çok uzak olmayan bir kod üretecektir. Ben genellikle sadece çok temel başlangıç ​​kodu, derleyiciden daha iyi optimize edebileceğim belirli alanlar veya hızlı kesmeler için veya kod boyutu kısıtlamaları gerektiriyorsa derleyici yazıyorum. Bugünlerde saf toplanma ihtiyacı yok.
19:12

1

Aşağıda, XC8 derleyicisini kullanarak satır içi montajla yapmanın yolu var ve şimdi çalışıyor ! Ancak, STATUSnormal kayıt için olduğundan daha zor görünüyor kayıt kaydetmek ve geri yüklemek için daha fazla kod geliştirmek gerekir .

Düzenle: Kod değiştirildi. Önceki kod içinlütfenbu yayının eski sürümlerine bakın.

/*
 * 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.
    }
}

Ve işte başlık dosyası 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 */

Kendi ödülünüzü kazanacaksınız. Tebrikler! :-)
stevenvh

@stevenvh Ah, bu oldu mu bilmiyor muyum? Teşekkürler :)
abdullah kahraman

İşe yaradığınız için tebrikler!
davidcary

Teşekkürler @davidcary! Tebrikler çocuklar için gerçekten minnettarım.
abdullah kahraman

1
STATUS'u gerçekten geri yüklemeniz mi gerekiyor? Öyleyse, "swapf" talimatını başka bir yerde belgelenen nedenlerle kullanmanız gerekir: " P. Anderson ", " Microchip Orta sınıf aile kılavuzu: bölüm 8.5 Bağlam Tasarrufu ", " PIC tasarrufu W ve DURUM "
davidcary

0

Aşağıda montaj kullanarak bu uygulama nasıl yapılır. Biçimlendirmeyle aynı koda erişin (Pastebin'e bağlantılar) . nasıl geliştirilebilir? Bu benim PIC meclisinde ilk programım, herhangi bir yorum takdir.

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.

Montajdaki ilk programınız çok görevli bir RTOS mu? Vay. Çoğu kişi yanıp sönen bir LED alabilirlerse gerçekten iyi gidiyor. :-).
davidcary

Aslında bu PIC mimarisindeki ilk montaj programım . Bundan önce, üniversitede 8086 ders aldım ama pratik değildi ve kendim öğrenmem gerekiyordu çünkü öğretim görevlisi bir yedekdi ve hiçbir şey bilmiyordu, ancak sınavlarda zor sorular soruyordu ..
abdullah kahraman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.