PIC x16 마이크로 컨트롤러를위한 반 선점 (협동) RTOS를 만들려고합니다. 내에서 이전의 질문에 나는 하드웨어 스택 포인터를 액세스하는 이러한 코어에 불가능하다는 것을 배웠다. 나는 살펴 보았다 이 PIClist 페이지, 이것은 내가 C를 사용하여 구현하기 위해 노력하고 무엇인가
내 컴파일러는 Microchip XC8이며 현재 구성 비트에서 4MHz 내부 RC 발진기가 선택된 PIC16F616을 작업 중입니다.
컴파일러의 헤더 파일을 보면서 C로 PCLATH 및 PCL 레지스터에 액세스 할 수 있다는 것을 배웠습니다. 그래서 간단한 작업 전환기를 구현하려고했습니다.
커서가 첫 번째 줄 ( TRISA=0;
)이 아닌 다른 줄 (예 :)에있을 때 커서를 다시 시작하고 재설정하고 커서로 PC를 설정 한 후 디버거를 일시 중지하면 디버거에서 원하는대로 작동합니다 ANSEL=0;
. 디버거를 처음 시작할 때 다음 메시지가 나타납니다 Debugger Console
.
Launching
Programming target
User program running
No source code lines were found at current PC 0x204
편집 : 나는 그것이 무엇이 작동했는지 알지 못하지만 디버거는 이제 완벽하게 작동합니다. 따라서 위의 출력과 단락을 생략하십시오.
편집 : 이와 같이 기본 정의를 변경하면 아래 코드가 작동합니다. 이것은 프로그램 주소에서 주요 기능을 시작합니다 0x0099
. 나는 이것을 일으키는 원인을 모른다. 이것은 실제 솔루션이 아닙니다. 컴파일러 특정 오류가 있다고 생각합니다.
void main(void) @ 0x0099
{
내 C 코드는 다음과 같습니다.
/*
* 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
}
}
그리고 여기 내 컴파일러가 만든 디스 어셈블리 목록 파일이 있습니다. 에서 시작합니다 line 74
.
실제 칩을 프로그래밍했으며 PORTA는 전혀 변경되지 않았습니다. 작동하지 않습니다.
프로그램이 작동하지 않는 이유는 무엇입니까?