PIC18F Kernel - 04

Post date: 11/01/2011 12:32:33

Nesta quarta parte abordaremos, dentro do processo de desenvolvimento do kernel, como garantir as necessidades temporais dos processos. Pra isso é necessário ter alguma ferramenta/dispositivo que permita a contagem do tempo. Para os microcontroladores este procedimento é feito através de um hardware dedicado. Neste artigo utilizaremos a interface "time.h" das bibliotecas padrões da ISO C.

Fonte da imagem: Wikipedia

A biblioteca time.h fornece ao programador uma série de funções interessantes para manipular o tempo, geralmente com base em algum contador do processador. Para nossa aplicação precisamos apenas de uma função que retorne o valor do tempo atual, para isso utilizamos o valor retornado pela função clock() dividido por (CLOCKS_PERSEC/1000). Deste modo o resultado é o tempo atual dados em millisegundos.

A primeira alteração necessária é na struct que define os processos. Agora ela deve conter também um campo indicando qual o intervalo requisitado para a função ser executada. Além do intervalo é necessário saber quando ela foi executada pela última vez. Para facilidade de implementação é melhor gravar, ao invés da última vez que foi executada, qual deve ser a próxima vez que o processo será executado.

//estrutura do processo

typedef struct {

ptrFunc Func;

int t_ms;

int start;

} processo;

Apenas as funções AdicionarProcesso() e ExecutaKernel() precisam ser executadas.

Na função AdicionarProcesso() será responsável por inicializar a função com o valor adequado no campo start, que será o próximo tempo no qual o processo será executado.

static int AddProc(processo newProc)

{

//para poder adicionar um processo tem que existir espaço

//o fim nunca pode coincidir com o inicio

if (((fim+1)%SLOT_SIZE)!= ini )//se incrementar nessa condição fim vai ficar igual à ini

{

vetProc[fim] = newProc;

vetProc[fim].start = clock()/(CLOCKS_PER_SEC/1000) + vetProc[fim].t_ms;//atualizando quando deve ser executada

fim++;

if (fim>=SLOT_SIZE) //loop da lista

{

fim = 0;

}

return FIM_OK; //sucesso

}

return FIM_FALHA;//falha

}

Na função ExecutaKernel() haverá um loop que ao invés de correr o buffer de processos executando um a um, devemos correr o buffer inteiro procurando o processo que está mais próximo de ser executado e os ordena. Após isso o kernel gasta tempo a toa esperando chegar ao tempo de executar a função. Após executar a função, se necessário reinsere a mesma no pool de funções.

static void ExecutaKernel(void)

{

int i,j;

int prox;

int now;

processo tempProc;

for(i=0; i<10;i++) //aqui entraria o loop infinito

{

if (ini != fim)

{

//Pega o tempo agora

now = clock()/(CLOCKS_PER_SEC/1000); //milissegundos

//Procura a próxima função a ser executada com base no tempo

j = ini;

prox = ini;

while(j!=fim)

{

if (vetProc[j].start < vetProc[prox].start)

{

prox = j;

}

j = (j+1)%SLOT_SIZE;

}

//troca e coloca o processo com menor tempo como a próxima

tempProc = vetProc[prox];

vetProc[prox] = vetProc[ini];

vetProc[ini] = tempProc;

while(now < vetProc[ini].start)

{

now = clock()/(CLOCKS_PER_SEC/1000); //milissegundos

}

printf("T:%d, Ite. %d, Slot. %d: ",now, i, ini);

//executa e vê se a funcao quer ser re-executada

if ( (*(vetProc[ini].Func))() == REPETIR )//retorna se precisa repetir novamente ou não

{

//coloca a função no fim da lista, esta posição esta sempre livre.

vetProc[fim] = vetProc[ini];

vetProc[fim].start += vetProc[fim].t_ms;

fim++;

if (fim>=SLOT_SIZE) //loop da lista

{

fim = 0;

}

}

//próxima função

ini++;

if (ini>=SLOT_SIZE) //loop da lista

{

ini = 0;

}

}

}

}

O tempo gasto a toa é necessário para garantir a sincronia, mas é uma ótima oportunidade de usar a economia de energia se o microcontrolador possui com instruções do tipo sleep/wait.

As alterações na função main são muito pequenas comparadas com as versões anteriores. Elas podem ser vista no arquivo em anexo a seguir.

No próximo artigo faremos as alterações necessárias para que este código execute no microcontrolador e abordaremos o inicio do desenvolvimento dos drivers.