Microcontroladores pic ling c unicamp
-
Upload
chico-fambrini -
Category
Engineering
-
view
283 -
download
14
Transcript of Microcontroladores pic ling c unicamp
Microcontroladores PIC
Linguagem CLinguagem C
Prof. Francisco Fambrini
Unicamp – Limeira - 2015
Livro recomendado para esta Aula
Disposição dos pinos PIC16F877
Estrutura básica interna de um micocontrolador
Estrutura de um programa em C
Resumo sobre declaração de variáveis e
operadores
Algumas configurações de fuse bits
Tipos de Variáveis em C
Modificadores signed e unsigned
Variáveis Globais
Exercícios de fixação
Operadores em C
Operadores relacionais em C
Operadores Lógicos
Operadores de atribuição
Operadores bit a bit
Adicionando botões na entrada do
microcontrolador
Lendo um botão em C
Nosso primeiro programa em C
// BOTAO E PISCA-LED
#include <16f877.h>
#use delay (clock=4000000)
#fuses XT, NOWDT,PUT,NOBROWNOUT,NOLVP, NOPROTECT
main( ){
While(TRUE){
IF (! INPUT (PIN_B0 )) { OUTPUT_LOW(PIN_B7);
DELAY_MS(300);
OUTPUT_LOW(PIN_B7);
DELAY_MS(300);
}
ELSE { OUTPUT_LOW(PIN_B7); }
}
}
Problema
Fazer o Projeto, para o controle da Bomba d’água B1, sendo que o nível
sempre estará entre S1 e S2 (sensores da bóia).
Quando o nível atinge o sensor S1 o seu contato fecha ligando a bomba dágua
para encher o tanque;Quando o nível atinge S2 a bomba deve ser
desligada para evitar que a água transborde.
Esquema do hardware proposto
Questões
Exemplo 2
• Dado o circuito do slide anterior, proponha para este
hardware um sequencial em firmware, capaz de
acender os leds um de cada vez, sendo que apenas
um led fica aceso a cada vez.
Quando o sensor S5 detecta a presença de uma pessoa a porta abrirá
rapidamente até que o sensor S3 seja atingido, onde a velocidade diminui
Quando chega a S4 o portão para, espera 15 segundos e a seguir, o portão
fecha. Chegando a S2 a velocidade diminui e em S1 o portão para. Considera
a velocidade lenta como uma saída VL e a rápida como VR. Faça o Projeto do
hardware e o esquema elétrico.
Pressionando o botão S1 o guindaste vai para a esquerda até o fim de curso S5
onde pára, só o botão S3 faz ao guindaste retornar até a posição S6. O botão S2
envia o guindaste para a direita até S7 e para retornar aperta-se o botão S4 fazendo o guindaste
retornar até S6.
Interrupções em C
1 - Dependem do Compilador.
2- Duas formas para o tratamento de interrupções no compilador PCHW da CCS:
• Automática:
O compilador gera todo o código do tratamento da interrupçãoO compilador gera todo o código do tratamento da interrupção
(flags, configuração de registradores , contexto, etc.)
A única tarefa do programador é a construção das funções de tratamento dos eventos individuais de cada interrupção.
• Manual:
O programador deverá se incumbir de tudo: verificar flags de interrupção, chamadas específicas para tratamento de cada evento, configuração dos registradores, salvar e recuperar contexto, etc.
O que são interrupções?
Interrupções, como o nome sugere, interrompem a execução normal e pedem atenção
urgente de CPU.
Interrupções são situações que a CPU não pode prever quando vai acontecer, elas podem
acontecer a qualquer momento, de modo que o CPU não pode esperar por elas.
Assim, a CPU continua fazendo seu trabalho normal a menos que interrupção ocorra.
Por exemplo, quando o USART (Hardware Comunicação Serial) receberá dados é
desconhecida, pode receber dados a qualquer momento.desconhecida, pode receber dados a qualquer momento.
Assim, a CPU continua a fazer o seu trabalho normal, que pode ser por exemplo ler a
temperatura de um sensor LM35 e mostrar no LCD.
A CPU continua a fazer o trabalho "normal", mas assim que a USART receber dados
informa a CPU usando uma interrupção. A CPU salva seu estado atual (para que ele
possa retornar a ele), e pula para a rotina de serviço de interrupção) ISR
imediatamente.
A Rotina ISR é geralmente muito pequena e rápida.
Assim que a ISR termina, a CPU restaura seu estado que foi salvo e retoma do ponto onde
ocorreu a interrupção.
Interrupções com tratamento Automático
e Manual
Interrupção Automática
• Vantagens: Simplicidade
• Desvantagens: Gera programas maiores.
Gera tempo extra no tratamento das interrupções,ou seja, o tempo entre aocorrência do evento de interrupção propriamente dito e o tratamento da mesma.
• Uso: Aplicações simples onde o tempo não é um fator crítico.• Uso: Aplicações simples onde o tempo não é um fator crítico.
Interrupção Manual
• Vantagens:
Adequado quando a aplicação demanda precisão de contagem.
• Desvantagens: Gera programas menores.
Mais trabalho para o programador. (contexto, flags,registradores, etc.)
• Uso: Aplicações de tempo real e/ou onde pequenos atrasos são indesejáveis.
• Observação!! Demanda inclusão de código assembler (diretiva específica)
Periféricos que geram interrupção no
PIC16F877
• Interrupção por overflow do Timer0;
• Interrupção RB (mudança de estado das portas B);
• Interrupção externa;
• Interrupção de conversão analógico/digital;
• Interrupção de transmissão de dados da porta serial (RS232);
• Interrupção de recepção de dados da porta serial (RS232);• Interrupção de recepção de dados da porta serial (RS232);
• Interrupção por overflow do Timer1;
• Interrupção por comparação do Timer2;
• Interrupção do módulo CCP1 e CCP2;
• Interrupção de atividade da comunicação SPI ou I2C;
• Interrupção de colisão de dados do barramento;
• Interrupção de escrita da EEPROM;
• Interrupção de evento do comparador.
INTCON: o registrador principal que
controla as interrupções
Algumas interrupções que serão
importantes para o Projeto Final
Hardware interno do microcontrolador
Exemplo: Configurar o TMR0 para que gere interrupções a cada 1 segundo.
//Após 125 estouros do TMR0 (125 interrupções), teremos chegado ao tempo de 1 segundo (1Hz).
#include <16F877A.h>
#use delay ( clock=4000000 )
#fuses HS,NOWDT,PUT,NOLVP
#int_timer0
void trata_tmr0 ( ) {
static boolean LED;
static int contador;
set_timer0(131 + get_timer0()) ;
contador++;
if( contador == 125) {if( contador == 125) {
contador = 0;
LED = !LED;
output_bit(pin_b0, LED); } }
void main( ) {
// configura o TMR0 para clock interno e prescaler dividindo por 64
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_64);
set_timer0 (131); // inicia o timer 0 em 131
// habilita interrupções
enable_interrupts (global | int_timer0);
while (true); // espera pela interrupção
}
Usar interrupção de Timer para gerenciar máquinas
de estado
Analise o código abaixo e diga o que ele faz
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
BYTE blink = 0;
#int_rb
void button_isr() {
delay_ms (20); //debounce
if( !input(PIN_B4) && !blink )
blink = 1;
else
if( !input(PIN_B4) && blink ) blink = 0; }
void main( ) {
enable_interrupts(global);
enable_interrupts(int_rb);
ext_int_edge( H_TO_L );
do { if(blink){ output_high(PIN_D1);
delay_ms(500);
output_low(PIN_D1);
delay_ms(500); }
} while (TRUE);
}
Usando o Conversor AD em C#include<16f877a.h>
#Device ADC=8
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=20000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
void main( ) {
int i, value, min, max;
printf("Sampling:");
setup_adc_ports( RA0_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
set_adc_channel( 0 );
do { // Toma 30 amostras do conversor AD aplicadas no pino A0
min = 255; // e mostra os valores mínimos e máximo dentre as 30 amostras
max = 0; // valores tomados em intervalos de 100ms
for(i = 0; i <= 30; ++i) {
delay_ms(100);
value = read_adc();
if(value < min)
min = value;
if(value > max)
max = value;
}
printf("nrMin:%x MAX: %x", min, max);
} while (TRUE);
}
No arquivo cabeçalho 16F877A.h encontramos as constantes:
• // Constants used in SETUP_ADC_PORTS() are:
• #define NO_ANALOGS 7 // None
• #define ALL_ANALOG 0 // A0 A1 A2 A3 A5 E0 E1 E2 Ref=Vdd
• #define AN0_AN1_AN2_AN4_AN5_AN6_AN7_VSS_VREF 1 // A0 A1 A2 A5 E0 E1 E2 Ref=A3
• #define AN0_AN1_AN2_AN3_AN4 2 // A0 A1 A2 A3 A5 Ref=Vdd
• #define AN0_AN1_AN2_AN4_VSS_VREF 3 // A0 A1 A2 A5 Ref=A3
• #define AN0_AN1_AN3 4 // A0 A1 A3 Ref=Vdd
• #define AN0_AN1_VSS_VREF 5 // A0 A1 Ref=A3
• #define AN0_AN1_AN4_AN5_AN6_AN7_VREF_VREF 0x08 // A0 A1 A5 E0 E1 E2 Ref=A2,A3
• #define AN0_AN1_AN2_AN3_AN4_AN5 0x09 // A0 A1 A2 A3 A5 E0 Ref=Vdd
• #define AN0_AN1_AN2_AN4_AN5_VSS_VREF 0x0A // A0 A1 A2 A5 E0 Ref=A3
• #define AN0_AN1_AN4_AN5_VREF_VREF 0x0B // A0 A1 A5 E0 Ref=A2,A3
• #define AN0_AN1_AN4_VREF_VREF 0x0C // A0 A1 A5 Ref=A2,A3
• #define AN0_AN1_VREF_VREF 0x0D // A0 A1 Ref=A2,A3• #define AN0_AN1_VREF_VREF 0x0D // A0 A1 Ref=A2,A3
• #define AN0 0x0E // A0
• #define AN0_VREF_VREF 0x0F // A0 Ref=A2,A3
• #define ANALOG_RA3_REF 0x1 //!old only provided for compatibility
• #define A_ANALOG 0x2 //!old only provided for compatibility
• #define A_ANALOG_RA3_REF 0x3 //!old only provided for compatibility
• #define RA0_RA1_RA3_ANALOG 0x4 //!old only provided for compatibility
• #define RA0_RA1_ANALOG_RA3_REF 0x5 //!old only provided for compatibility
• #define ANALOG_RA3_RA2_REF 0x8 //!old only provided for compatibility
• #define ANALOG_NOT_RE1_RE2 0x9 //!old only provided for compatibility
• #define ANALOG_NOT_RE1_RE2_REF_RA3 0xA //!old only provided for compatibility
• #define ANALOG_NOT_RE1_RE2_REF_RA3_RA2 0xB //!old only provided for compatibility
• #define A_ANALOG_RA3_RA2_REF 0xC //!old only provided for compatibility
• #define RA0_RA1_ANALOG_RA3_RA2_REF 0xD //!old only provided for compatibility
• #define RA0_ANALOG 0xE //!old only provided for compatibility
• #define RA0_ANALOG_RA3_RA2_REF 0xF //!old only provided for compatibility
SETUP_ADC( )
Set_adc( ) e read_adc( )
Quais são os problemas com esse projeto de
hardware ?
Exemplo de configuração dos 2 canais de PWM
#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
main( ) {
output_low(PIN_C1); // Set CCP2 output low
output_low(PIN_C2); // Set CCP1 output low
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP2 as a PWM
setup_timer_2(T2_DIV_BY_16, 124, 1); // 500 Hz
set_pwm1_duty(31); // 25% duty cycle on pin C2
set_pwm2_duty(62); // 50% duty cycle on pin C1
while(1); // Prevent PIC from going to sleep (Important !)
}
Equações usadas para ajustar os valores do
PWM no CCS
value = Fosc / (Fpwm * 4 * T2DIV) - 1
setup_timer_2(T2_DIV_BY_X, value, 1);
valor = (Desired_Duty_Cycle% * Fosc) / (Fpwm * 4 * T2DIV)
set_pwm1_duty(valor);
Exercício
A cada 2 segundos o microcontrolador deve adicionar à sua saída analógica 0,5
volt, até alcançar 5 volts. Isto será iniciado quando o operador pressionar o botão
start, e quando for pressionado o botão stop a rampa deverá ser decrescente
até o motor parar. Para este problema assuma que a saída analógica é a saida do
PWM 1.
Memória de dados não voláteis:
Eeprom
Para escrever na EEPROM
Write_eeprom ( end. , valor);
Para ler o conteúdo de um determinado endereço:Para ler o conteúdo de um determinado endereço:
x = read_eeprom (end.);
Obs: valor deve ser um inteiro de 8 bits ! ( int8)
Memória de dados não voláteis: Eeprom -
exemplo
#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#rom 0x2100 = { 7, 39 } // Diretiva #ROM inicializa a EEPROM
#include <lcd2.c>
void main( ) {
int8 value, value1;int8 value, value1;
lcd_init( );
value = read_eeprom (0x2100);
value1= read_eeprom (0x2101);
delay_ms(6);
lcd_gotoxy(1,1);
printf(lcd_putc," Prof. Fambrini ");
lcd_gotoxy(1,2);
printf( lcd_putc,"D1=%u",value);
lcd_gotoxy(9,2);
printf(lcd_putc,"D2=%u",value1) ;
while(TRUE) { }
}
Como guardar um número Float ou um int32 na
Eeprom ?
//*********************** Gravando Float na EEPROM *****************************//
void WRITE_FLOAT_EEPROM (int8 n, float data){
int8 i;
for (i = 0; i < 4; i++)write_eeprom (i + n, *(&data + i) ) ;
}
//**************************** Lendo Float na EEPROM *************************//
float READ_FLOAT_EEPROM (int8 n){
int8 i ;float data;
for (i = 0; i < 4; i++)*(&data + i) = read_eeprom (i + n);
return(data);}