As vezes precisamos usar um microcontrolador como o nosso "pequeno notável" PIC12F675, pois tem somente 8 pinos ficando ideal para aplicações em que a simplicidade e redução de tamanho são significativo,mas apesar de contar com um conversor analógico digital não tem uma porta serial para entregar uma informação, qual a solução? Isso mesmo criar uma porta serial virtual ou seja emular uma porta serial.Esse algoritmo pode ser usado em outros microcontroladores para ser ter mais portas seriais(sem a necessidades de comprar um microcontrolador dedicado).
A primeira coisa que deve ser feita é escolher o cristal a ser utilizado pois a velocidade de comunicação depende disto,neste exemplo vou colocar pra 3 tipos de configurações:usando o oscilador interno,usando um cristal externo de 4MHZ e usando um cristal de 20MHZ.
Para ajustar os tempos de bits tive que definir 2 variáveis de controle ; "TIME_BAUD" ,usado pela transmissão e "BAUD_RX" usado pela recepção(o motivo desta variável é compensar atrasos de leitura do pino),as velocidades testadas foram 4800bps,9600bps e 19200bps, os tempos de cada bit são 208us,104us e 52us respectivamente.
Para o cristal de 4MHZ ou o oscilador interno(que é de 4MHZ mas é do tipo RC) o melhor desempenho foi na faixa de 4800bps, enquanto o de 20MHZ funcionou bem nas três velocidades, pois os tempos de execução de rotina se tornam pouco expressivo nos tempos de envio e recepção.Os resultados foram colocados no final do código para ajudar a orientar no processo de uso do algoritmo.
Neste exemplo o ao ser ligado o circuito ele envia uma mensagem para que o usuário digite algo no terminal serial e então repete o carácter, conta ainda com um botão que ao ser pressionado enviar o carácter "A", veja abaixo como ficou o código fonte e a simulação:
O código-fonte:
/* * Emulando(cria uma porta virtual) uma porta serial * * Compilador : MPlabXC8 V.3.0 * Data: 28/08/2015. * Microcontrolador: 12F675. * Autor: aguivone. * Versão: 1. * * Emulado para 8 bits de dados/sem paridade/1bit de stop bit * Emulado para 1 bit de start e stop * sem paridade * * Antes de usar leia os parametros no final do codigo. */ #include <stdio.h> #include <stdlib.h> #include <string.h>//para trabalhar com string #include <xc.h> #define _XTAL_FREQ 20000000//usado pela rotina de tempo do pic /////////////////////////////////////////////////////////configuraçôes////////////////////////////////////////////////// #pragma config FOSC = HS // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-Up Timer Enable bit (PWRT enabled) #pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD) #pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled) #pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled) #pragma config CPD = ON // Data Code Protection bit (Data memory code protection is enabled) #define BOT GP2//configura o pino que será RX ///parametros da porta serial emulada//////////////////////////////////////////////////////////////// #define TIME_BAUD 45//19200 bps - 20MHZ #define BAUD_RX 42//19200 bps - 20MHZ #define TX GP0//configura o pino que será TX #define RX GP1//configura o pino que será RX ///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////Funçoes utilizadas///////////////////////////////////////////////////////////// void escreve_char(char dados) { int contagem = 0; TX = 0; while (contagem < 8) //envia dados + stop bit { __delay_us(TIME_BAUD); if ((dados & 0X01) == 0X01) //testa bit menos significativo (LSB) { TX = 1; } else { TX = 0; } dados = dados >> 1; //rotaciona bit contagem++; } __delay_us(TIME_BAUD); //tempo do ultimo bit TX = 1; //volta pra nivel alto (fim de transmissão de caracter) __delay_us(TIME_BAUD); //stop bit } ///é interessante observar que está rotina irá trabalhar melhor se for ///usado na rotina de interrupção de estado no pino, aqui vou deixar na rotina principal por // ser um exemplo simples char ler() { int contagem = 0; char RX_dados = 0X00; if (RX == 0)//tem dados pra ler { RX_dados = 0X00; while (contagem < 8) //recebe dados + stop bit { __delay_us(BAUD_RX); //compensa algum delay na recepção if (RX == 1) { RX_dados = (RX_dados | 0X80); //seta bit mais significativo (MSB) } RX_dados = RX_dados >> 1; contagem++; } contagem = 0; while ((RX == 0) && (contagem < 4)) { contagem++; //time out para não travar,tempo de 4 bits __delay_us(TIME_BAUD); } } return (RX_dados); } void escreve_frase(char *frase) { int tam_frase = strlen(frase); int contagem = 0; while (contagem < tam_frase) { escreve_char(frase[contagem]); contagem++; } } //////////////////////////////////////////////////////Rotina principal/////////////////////////////////////////////////////////////// void main(void) { TRISIO = 0X06; //configura gp1 e gp2 como entrada CMCON = 7; //desabilita comparadores ANSEL = 0; //habilita as portas de I/O char teste; TX = 1; //prepara pino de TX escreve_frase("testando comunicação serial emulada!"); escreve_frase("\n\r digite algo?"); for (;;) { if (BOT == 1) {//quando o botão é pressionado escreve 1 caracter escreve_char('A'); __delay_ms(100); } teste = ler(); //verifica se tem dados pra ser lido if (teste != 0X00)//tem dados se for diferente de 0X00(este caracter pode ser alterado) { escreve_frase("\n\r"); escreve_frase("Caracter digitado = "); escreve_char(teste); //escreve o caracter digitado } } } //NOTAS DE PARAMETRIZAÇÃO: //*********************************************************************************************************** //oscilador interno do pic 12F675(testado fisicamente )////////////////////////////////////////////////////// // configure assim o fuse do oscilador interno => #pragma config FOSC = INTRCIO // configure assim o fuse do cristal de 4MHZ => #pragma config FOSC = XT // //#define TIME_BAUD 14//19200 bps - 4MHZ - usando cristal //#define TIME_BAUD 16//19200 bps - 4MHZ - usando oscilador interno //#define BAUD_RX 12//19200 bps - 4MHZ - osc. interno - recepção não fica confiavel //#define TIME_BAUD 68//9600 bps - 4MHZ - usando oscilador interno //#define BAUD_RX 58//9600 bps - 4MHZ - cristal 4MHZ - recepção funcionou bem(houve pouquissimo erros) - no proteus esse valor não funciona //#define BAUD_RX 60//9600 bps - 4MHZ - recepção funcionou bem(houve pouquissimo erros) //#define TIME_BAUD 175//4800 bps - 4MHZ //#define BAUD_RX 165//4800 bps - 4MHZ - recepção funcionou muito bem(100% confiavel fisicamente, mas no proteus apresenta falhas) //************************************************************************************************* // oscilador com cristal de 20MHZ (testado fisicamente funcionou ok) // configure assim o fuse do cristal => #pragma config FOSC = HS //#define TIME_BAUD 45//19200 bps - 20MHZ //#define BAUD_RX 42//19200 bps - 20MHZ //#define TIME_BAUD 97//9600 bps - 20MHZ //#define BAUD_RX 95//9600 bps - 20MHZ //#define TIME_BAUD 202//4800 bps - 20MHZ //#define BAUD_RX 198//4800 bps - 20MHZ
A simulação:
Nenhum comentário :
Postar um comentário
olá,digite aqui seu comentário!