4. ROTINA DE FALHA
A rotina de falha para qual o microcontrolador é desviado no caso de falha de configuração dos clocks de sistema utilizando os valores pré-calibrados de DCO nada mais é do que um loop infinito para evitar que o mesma vá para algum estado inesperado.
void FaultRoutine(void) {
while(1);
while(1);
}
5. TIMER
Como explicado na primeira parte, a minha idéia é utilizar o bloco 0 para estabelecer a freqüência de
dois sinais PWM (TACCR0), e usar os outros dois módulos para gerenciar o
duty-cycle de maneira independente desses dois sinais (TACCR1 e TACCR2).
Não vou entrar em detalhes de como a coisa funciona pois isso está na primeira parte bem detalhado.
Antes de mais nada, vamos escolher a frequencia do PWM que queremos gerar. Para facilitar, vamos gerar um sinal de 1kHz. Com isso em mente, vamos calcular qual deverá ser o valor do registrador TA1CCR0 para que ele seja resetado a cada 1mS (e com isso gerar um sinal de 1kHz).
A primeira coisa a ser configurada deve ser a fonte de clock para esse periférico. Inicialmente, levando em conta que configuramos o clock do dispositivo conforme post anterior, deveremos ter o SMCLK com 1MHz oriundos do DCO interno. Para facilitar, vamos configurar o timer para que o SMCLK seja a sua fonte de clock e sem dividir (ou dividir esse clock por 1). Além disso, vamos também configurar ele para que trabalho no modo "up", conforme explicado na primeira parte desse tutorial. Dessa forma, o TA1CCR0 irá contar do valor 0 (zero) até o valor configurado, quando será resetado e iniciará nova contagem.
TA1CTL = TASSEL_2 + MC_1 + ID_0;
// TACTL = 0x0200 + 0x0010 = 0x0210
// TASSEL_2 -> SMCLK como fonte de clock para o timer
// MC_1 -> up mode: timer conta até o valor de CCR0
// ID_0 -> entrada de clock dividida por 1
// TACTL = 0x0200 + 0x0010 = 0x0210
// TASSEL_2 -> SMCLK como fonte de clock para o timer
// MC_1 -> up mode: timer conta até o valor de CCR0
// ID_0 -> entrada de clock dividida por 1
Sabendo que o clock que alimentará o sistema terá uma frequencia de 1MHz (período de 1uS), vamos calcular qual deverá ser o valor do registrado TA1CCR0 para que o mesmo gere uma frequencia de 1kHz, ou seja, que ele estoure a cada 1mS.
TA1CCR0 = 1mS/1uS = 1000
Levando em conta que a contagem se inicia em 0 e não em 1, então o valor inicial do TA1CCR0 deverá ser 1000-1=999. Além disso, vamos configurar os outros dois blocos de comparação/captura no modo reset/set, conforme já explicado na primeira parte desse tutorial.
TA1CCR0 = 1mS/1uS = 1000
Levando em conta que a contagem se inicia em 0 e não em 1, então o valor inicial do TA1CCR0 deverá ser 1000-1=999. Além disso, vamos configurar os outros dois blocos de comparação/captura no modo reset/set, conforme já explicado na primeira parte desse tutorial.
TA1CCR0 = PWM_periodo-1;// PWM Period
TA1CCTL1 = OUTMOD_7; // CCR1 reset/set
TA1CCTL2 = OUTMOD_7; // CCR2 reset/set
TA1CCR1 = 500; // CCR1 PWM duty cycle
TA1CCR2 = 900; // CCR2 PWM duty cycle
TA1CCTL1 = OUTMOD_7; // CCR1 reset/set
TA1CCTL2 = OUTMOD_7; // CCR2 reset/set
TA1CCR1 = 500; // CCR1 PWM duty cycle
TA1CCR2 = 900; // CCR2 PWM duty cycle
Fazendo TA1CCR1 = 500, teremos um duty cycle perto dos 50% (lembre-se de que o total é de 1000, valor inicial do TA1CCR0), então cada ciclo deverá ter perto de 500uS ou 0,5mS. Para o TA1CCR2, o duty cycle deverá ser de 90%.
6. CÓDIGO COMPLETO
Abaixo disponibilizo o código completo da aplicação. Ao contrário do que disse na parte anterior, eu acabei deixando omicrocontrolado em Low Power Mode (LPM0).
#include "msp430G2553.h"
void FaultRoutine(void); //
void ConfigWDT(void); // Configuração do Watchdog
void ConfigClocks(void); // Configuração dos Clocks dos sistemas
void ConfigPins(void);
void ConfigTimerA1(void);
void ConfigPWM(unsigned int value1, unsigned int value2);
#define PWM_periodo 1000
void main(void){
ConfigWDT(); // Configura WatchDog Timer
ConfigClocks(); // Configura Clocks do Dispositivo
ConfigPins(); // Configura Pinos do Dispositivo
ConfigTimerA1(); // Configura Timer A1
// ConfigPWM();
_BIS_SR(LPM0_bits); // entra no modo LPM0
}
void FaultRoutine(void) {
while(1); // TRAP
}
void ConfigWDT(void) {
WDTCTL = WDTPW + WDTHOLD; // Desliga Watchdog
}
void ConfigClocks(void){
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) // verifica se os valores de calibração do Clock é válido
FaultRoutine(); // se não for válido então entra nessa rotina
BCSCTL1 = CALBC1_1MHZ; // Configuração da faixa DCO
DCOCTL = CALDCO_1MHZ; // Configuração dos DCO step e Modulo
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
IFG1 &= ~OFIFG; // Reseta OSCFault flag
BCSCTL2 |= SELM_0 + DIVM_0 + DIVS_0; // SELM_0 = seleciona Master Clock como sendo DCO; MCLK = DCO, SMCLK = DCO
}
void ConfigPins(void){
// PxDIR -> direção do pino (1=saída; 0=entrada)
P2DIR |= (BIT2+BIT4); // P2.2 e P2.4 como output
P2SEL2 = 0;
P2SEL |= (BIT2+BIT4); // P2.2 para TA1.1 e P2.4 para TA1.2
// P2REN = 1;
}
void ConfigTimerA1(void){
TA1CCR0 = PWM_periodo-1;// PWM Period
TA1CCTL1 = OUTMOD_7; // CCR1 reset/set
TA1CCTL2 = OUTMOD_7; // CCR2 reset/set
TA1CCR1 = 500; // CCR1 PWM duty cycle
TA1CCR2 = 900; // CCR2 PWM duty cycle
}
void ConfigPWM(unsigned int value1, unsigned int value2){
TA1CCR1 = value1; // CCR1 PWM duty cycle
TA1CCR2 = value2; // CCR2 PWM duty cycle
}
7. RESULTADOS
A seguir temos imagens das capturas realizados nos pinos em que os PWMs foram configurados (clique para ampliar). No primeira figura, vemos que o valor do período ficou bem próximo aos 1mS (1000uS) e o duty cycle para o primeiro PWM também ficou bem próximo aos 50% (0,5mS ou 50uS) desejados e o do segundo perto dos 90% (0,9mS ou 900us)
Captura dos PWMs gerados: período para o duty cycle de 90%. |
Captura dos PWMs gerados: período para o duty cycle de 50%. |
Nenhum comentário:
Postar um comentário