Trabalho nº 9 PARTE_II Voltimetro digital Resumo: Voltimetro digital 0..5 Volts visualização através da USART do PIC Nome ficheiro: trab9voltuart.asm * Data: 1/Junho/2005 * Versão: 1.0 * Autores: José Miguel Gaspar * Olímpia Rodrigues * Orientador: Prof. José Luís Azevedo * Universidade de Aveiro * Seminário EEI 2004/2005 * Ficheiro necessário: P16F876.INC * list p=16f876 list directive to define radix decimal processor #include "p16f876.inc" errorlevel -302 processor specific variable definitions Turn off banking message known tested (good) code -------------------------------------------------------------------- Constantes -------------------------------------------------------------------- RC0 EQU 0 RC1 EQU 1 RC2 EQU 2 RC3 EQU 3 RC4 EQU 4 RC5 EQU 5 RC6 EQU 6 RC7 EQU 7 RB0 EQU 0 RB1 EQU 1 RB2 EQU 2 RB3 EQU 3 RB4 EQU 4 RB5 EQU 5 RB6 EQU 6 RB7 EQU 7 RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 TMR0_HW_VAL1 EQU 255 25us aproximadamente ANALOG_CHANNEL EQU 0 Analog Channel 0(AN0) N_SHIFTS EQU 5 ---------------------------------------------------------------------- Variáveis (REGISTOS DE USO GERAL) ---------------------------------------------------------------------- variaveis UDATA 0x20 aux RES 1 valor_tensao RES 1 dig_high RES 1 dig_low RES 1 divdo RES 1 i RES 1 j RES 1 1
value_xg_high RES 1 value_xg_low RES 1 value_low RES 1 value_high RES 1 prt_count RES 1 prt_pos RES 1 buffer_32 RES 32 C:\seminario\guiao_aluno\trab9\trab9p2\trab9VoltUart.asm -------------------------------------------------------------------- Macros to select the register Banks -------------------------------------------------------------------- Bank0 MACRO Macro to select data RAM Bank 0 bcf STATUS,RP0 bcf STATUS,RP1 Bank1 MACRO Macro to select data RAM Bank 1 bsf STATUS,RP0 bcf STATUS,RP1 Bank2 MACRO Macro to select data RAM Bank 2 bcf STATUS,RP0 bsf STATUS,RP1 Bank3 MACRO Macro to select data RAM Bank 3 bsf STATUS,RP0 bsf STATUS,RP1 ORG 0x0000 Processor reset vector clrf PCLATH Ensure page bits are cleared goto main Go to beginning of program ==================================================================== ORG 0x0005 data_table table for strings addwf PCL,f "XXXXXXXXXXXXXXXXXXXX" ptr_string: dt "Valor U digite 'v' "posição - 0 dt " - Volts "posição - 20 "XXXXXXXXXXXXXXXXXXXX" main call InitCfg Aqui começa o programa principal while_1 movlw 0 call prt_string posição 0 da 'dt' movlw buffer_32 inicialize pointer call write_buff_32 void write_buffer(char* buff) movlw buffer_32 char media_32(char* buff) call media_32 call xg_scale call itoa call rx_char sublw 'v' btfss STATUS,Z goto $-3 movfw dig_high unidades de tensão call tx_char movlw '.' '.' call tx_char movfw dig_low decimas de tensao call tx_char movlw 20 call prt_string posição 20 da 'dt' goto while_1 2
************************** ROTINAS ********************************* InitCfg Configuração inicial dos registros associados ao programa principal, PORTS I/O, Timer0, ADC, USART Retorna em Bank0 InitCfg ----------------- Config USART ------------------------------------ Bank1 DATA memory (RAM) Bank1 movlw 10 115.2 Kbaud @ 20MHz movwf SPBRG clrf bsf bsf TXSTA TXSTA,TXEN TXSTA,BRGH Bank0 DATA memory (RAM) Bank0 clrf RCSTA bsf RCSTA,SPEN SPEN = 1 bsf RCSTA,CREN CREN = 1 --------------- Analog 2 Digital - Config ------------------------- Bank1 DATA memory (RAM) Bank1 clrf ADCON1 bsf ADCON1,PCFG3 PCFG3 = 1 bsf ADCON1,PCFG2 PCFG2 = 1 bsf ADCON1,PCFG1 PCFG1 = 1 bcf ADCON1,PCFG0 PCFG0 = 0 RA0 = input analógico Bank0 DATA memory (RAM) Bank0 clrf ADCON0 bsf ADCON0,ADCS1 bcf ADCON0,ADCS0 FOSC / 32 bsf ADCON0,ADON ADC ON ---------------- I/O - Config ------------------------------------- Bank1 memoria do programa em Bank1 movlw b'00000001' RA[7:1] outputs movwf TRISA RA[0] input ----------------- TRM0 - Config ------------------------------------ clrf OPTION_REG clear OPTION_REG bsf OPTION_REG,INTEDG INTEDG = 1 bsf OPTION_REG,PS2 bsf OPTION_REG,PS1 TMR0 Rate bcf OPTION_REG,PS0 1:128 Bank0 DATA memory (RAM) Bank0 movlw TMR0_HW_VAL1 Set Hardware timer0 Value movwf TMR0 Set TMR0 Transmit Char = tx_char Input: W(reg) - Character ASCII a transmitir Output: não devolve nada A rotina tx_char, aguarda que a FLAG TXIF de PIR1 seja 1, sinalizando assim a autorização de envio de um char através de TXREG. void tx_char(char c) tx_char btfss PIR1,TXIF while( TXIF == 0) {} goto $-1 movwf TXREG 3
C:\seminario\guiao_aluno\trab9\trab9p2\trab9VoltUart.asm Receive Char = rx_char Input: não têm parâmetro de entrada Output: W(reg) - Character ASCII recebido através da USART A rotina rx_char, aguarda que a FLAG RCIF de PIR1 seja 1, sinalizando assim a chegada de um char ao registo RCREG. char rx_char(void) rx_char btfss PIR1,RCIF while( RCIF == 0) {} goto $-1 movfw RCREG print_string - prt_string Input: prt_pos - localização do caracter na tabela Output: não têm parametro de saída Esta rotina imprime no ecra 20 caracteres, posicionadas na 'dt' (tabela de dados) através do parametro 'prt_pos'. void prt_string(unsigned char prt_pos) prt_string movwf prt_pos movlw 20 print 20 character / line movwf prt_count prt_next_char movlw HIGH data_table initialize PCLATH reg movwf PCLATH before using addwf PCL,f when ing from routine movfw prt_pos character table location call data_table retrieve 1 character call tx_char send character to USART incf prt_pos,f get next character to send decfsz prt_count,f move pointer to next char goto prt_next_char movlw '\r' call tx_char movlw '\n' call tx_char Input: W(reg) - ponteito para o endereço de buffer_32 Output: - não têm parametro de saída Recolhe 32 valores da ADC[0..255], escrevendo os mesmos em 32 posições consecutivas de memória RAM void write_buff_32(char* buffer_32) write_buff_32 movwf FSR initialize pointer write_again movlw ANALOG_CHANNEL w(reg) = analog_channel call analog2digital analog2digital(char W(reg)) movwf INDF write INDF register incf FSR,f inc pointer btfss FSR,5 all done? goto write_again no write again yes Input: W(reg) - Canal de entrada AN<X> em que X[0:7] Output: W(reg) - valor de saída convertido pela ADC (formato digital) escala (0..255) em que 0 = gnd e 255 = VREF+ = 5V 4
Devolve em W(reg) valor digital convertido pela ADC. char analog2digital(unsigned char canal_adc) analog2digital andlw 0x07 movwf aux aux = 0x07 & w bcf STATUS,C rlf aux,f rlf aux,f rlf aux,f movlw 0xC7 andwf ADCON0,w iorwf aux,w movwf ADCON0 btfss INTCON,T0IF while(toif == 0) {} goto $-1 bcf INTCON,T0IF T0IF = 0 movlw TMR0_HW_VAL1 Set Hardware timer0 Value movwf TMR0 Set TMR0 bsf ADCON0,GO início da conversão btfsc ADCON0,GO goto $-1 movfw ADRESH Input: W(reg) - ponteiro para o buffer Output: W(reg) - média aritmética das 32 amostras Soma os 32 resultados de conversão da ADC, presentes no buffer de de 32 posições, devolvendo a sua média aritmética. char media_32(char* buffer_32) media_32 clrf value_low initialize register clrf value_high initialize register movwf FSR initialize pointer read_again movfw INDF read INDF register to W(reg) call soma soma(char W(reg)) incf FSR,f inc pointer btfss FSR,5 all done? goto read_again no read again yes continue movlw N_SHIFTS movwf aux divide_again bcf STATUS,C next - > Carry = flag = 0 rrf value_high,f msb_value_high = 0 rrf value_low,f decfsz aux,f all done? goto divide_again no divide again movfw value_low yes (value_low in W) Input: W(reg) - valor de 8 bits a somar com os 8 bits menos significativos de value low Output: não têm parâmetro de saída Soma o valor actual com o anterior se existir CARRY, incrementa o valor de value_high de uma unidade. void soma(unsigned char val_buffer_32) soma addwf value_low,f value_low + W(reg) btfsc STATUS,C exist CARRY? incf value_high,f yes, inc value_high 5
no, Input: W(reg) - valor hex na escala de (0..255) Output: W(reg) - valor hex na escala de (0..50) Mudança de escala [0..255] -> [0..50] char xg_scale(unsigned char val) xg_scale movwf value_xg_low movlw 0x32 movwf i i = 0x32 movfw value_xg_low clrf value_xg_high add_again addwf value_xg_low,w w = w + value_xg_low btfsc STATUS,C exist CARRY? incf value_xg_high,f yes, inc value_xg_high decfsz i,f no, decrement i goto add_again if ( i!= 0 ) movfw value_xg_high if ( i == 0 ) Input: W(reg) - valor de 8 bits em hexadecimal 0x?? Output: W(reg) - valor de 8 bits equivalente em decimal Equivalente em Linguagem C char h2d (char value_low) { ((value_low/10 << 4) + (value_low % 10) } h2d movwf divdo temp = w = value_low clrf j j = 0 movlw 10 while( divdo >= 10) next_sub subwf divdo,f se o subtraendo >= ao subtractor => CY = 1 se o subtraendo < ao subtractor => CY = 0 btfss STATUS,C divdo -=divdo goto fwd } incf j,f goto next_sub fwd addwf divdo,f swapf j,w addwf divdo,w w = temp + count w => valor decimal correspondente a value_low(hex) Input: w = valor de entrada em decimal a converter ASCII Output: dig_high = unidades dig_low = decimas Devolve o valor ascii das unidades e das decimas do valor em tensão char* itoa( char val) itoa call h2d movwf dig_low digito = w = val movwf dig_high movlw 0x0f andwf dig_low,f movlw '0' addwf dig_low,f dig_low +='0' swapf dig_high,f movlw 0x0f andwf dig_high,f movlw '0' addwf dig_high,f 6
END directive 'end of program' 7