Curso de programación en C para microcontroladores PIC

De todas formas, cuando se mezclan assembler y C, hay que tener en cuenta el estado de los registros al momento de llamar a una función en assembler desde C, porque tal vez el código en C utilizaba algunos registros. Eso dependerá del uC y tal vez del compilador, pero hay que tenerlo en cuenta.
 
Una pregunta, estoy usando XC8, me gusta la programación más universal y siempre he tenido mis momentos de discusión con los PIC y el acceso a sus registros de una forma que no es tan estándar, cosa que obliga a reescribir medio programa si pasas a otro.

Mi problema es que quería ejecutar una simple instrucción PORT ^= PIN para hacer destellar el LED, esto funciona en MSP430, AVR y ARM, pero por algún motivo, no lo hace en el PIC, no se si es cosa del compilador o que, siento que no traduce la instrucción. ¿hay algo que haga mal? básicamente solo es eso en bucle while(1) y un delay. ¿no se puede usar bitwise directamente en los puertos?
 
A mi me pasó lo mismo, y he visto que los compiladores no siempre interpretan las instrucciones de la misma forma.

En XC8 un bit toggle, me funcionó con las siguientes instrucciones:
Ejemplo para el bit RB4.
PORTBbits.RB4 ^= 1;
Y esta otra forma también funciona:
PORTBbits.RB4 = PORTBbits.RB4 ^ 1;
 
No se en XC8, pero en CCS el modo de operacion por defecto de los puertos es algo medio raro, y para que funcione "como uno espera que lo haga" hay que cambiar el modo de operacion con la directiva #fast_io (o algo parecido)
 
creo que tiene que ver mucho con el modo de operación de los PIC, eso de tener que mover todo a W, así está el programa, en GP5 si destella, pero en GP4 no lo hace

Código:
/* 
 * File:   Main.c
 * Author: nuyel
 *
 * Created on 21 de febrero de 2017, 11:08 PM
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// PIC12F675 Configuration Bit Settings

// 'C' source line config statements

// CONFIG
#pragma config FOSC = INTRCIO   // 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 = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#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 = OFF        // Data Code Protection bit (Data memory code protection is disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.


/*
 * 
 */
#define LEDBIT _GPIO_GPIO4_MASK
#define _XTAL_FREQ 4000000

//__CONFIG(MCLRE_OFF & CP_OFF & BOREN_OFF & WDTE_OFF & FOSC_INTRCIO & PWRTE_ON);

void main() {
    TRISIO = 0;
    GPIO = 0;
    while(1){
        GPIObits.GP4 ^= 1;
        GP5 = 1;
        __delay_ms(500);
        GP5 = 0;
        __delay_ms(500);
    }
}

Supongo que no podré escribir un código más universal sin tener que agregar toda una HAL para manejar esas peculiaridades de los PIC, ahora recuerdo el por qué nunca quise aprender de ellos realmente.

Agrego, es un PIC12F675.
 
Cada ves mas problemáticos, normalmente cuando algo no se usa en otro microcontrolador se inicia desactivado como predeterminado, supongo que el error viene por que el PIC opera con Read-Modify-Write, con ANSEL sin configurar los pines devolvían 0 por lo que el bitwise operaba en 0 siempre.

Ahora ya funciona el PORT ^= PIN;
 
Cada ves mas problemáticos, normalmente cuando algo no se usa en otro microcontrolador se inicia desactivado como predeterminado, supongo que el error viene por que el PIC opera con Read-Modify-Write, con ANSEL sin configurar los pines devolvían 0 por lo que el bitwise operaba en 0 siempre.
Pues no es así.
En los compiladores en donde puedes manipular los registros, cómo el caso de XC Compiler, hay que tener eso en cuenta al inicializar los registros.
Mira la hoja de datos y verás cómo se inicia el registro ANSEL en un Power On Reset (POR) y en el Brown Out Detect (BOD)
12F675 - Special Function Registers (ANSEL).jpg
Entonces sin configurar ANSEL, se tendrá: 0b00001111 = 0x15, por defecto.
Lo que establece a GP4 (ANS3) como entrada análoga.
12F675 - ANSEL Register.jpg

En cambio, el compilador PCWHD de CCS, establece todo digital por defecto.
Y por lógica, al ser de alto nivel, establece muchas cosas más para una inicialización adecuada.
Sin embargo, tenemos la opción de declarar los registros y configurarlos cómo uno quiera. ;)
 
Última edición:
saben anteriormente eh trabajado con el BASIC la cual contiene la funcion SERIN la cual me permite obtener un dato serial LA CUAL LO ESPERO CIERTO TIEMPO pero en el caso del ccs no sè si tiene una funcion parecida,por que con la funcion GETCH se me queda indefinidamente esperando el dato y no me permite continuar con las tareas o saber si el pic sigue en funcionamiento
 
Si se puede, pero lo debes especificar en la configuración de #USE RS232 (Usando timeout = xxx en ms)
Lee la ayuda y busca: getc_timeout. No es una instrucción, pero encontrarás un ejemplo.
 
ahh cuando hablas de esos registros en los mensajes anteriores el ccs tiene funciones que acceden a los registros ya sea de interrupciones o flags sin embargo no creo que contenga todos los que dispone un pic ,por ello mi pregunta en el caso del ansel como puedo acceder a este registro y a los demás por que en el ccs no me deja declararlo como el programa de NUYEL el cual esta en otro compilador ,pienso que al declararlo ¿deberia estar en forma de assembler? bueno por que sino no me pueden funcionar bien los pines analógicos si los quiero utilizar como digitales ,de antemano gracias por su respuesta
 
Eso es raro, por que xc.h solo es un link al correspondiente picxxx.h de microchip y esas generalmente siempre son iguales, ANSEL es un puntero, lo que si me es incomodo es el como se declaran los valores en las cabeceras y luego no funcionan a como uno está acostumbrado, prácticamente los PIC usan un C muy diferente, de hecho he pensado en hacer mi propia cabecera para usar un C más normalizado al programar.

En mi cabecera viene como:
Código:
extern volatile unsigned char           ANSEL               @ 0x09F;
#ifndef _LIB_BUILD
asm("ANSEL equ 09Fh");
#endif
 
Cuando hablas de esos registros en los mensajes anteriores, el CCS tiene funciones que acceden a los registros ya sea de interrupciones o flags, sin embargo no creo que contenga todos los que dispone un PIC, por ello mi pregunta en el caso del ANSEL.
¿Cómo puedo acceder a este registro y a los demás?
Declarándolo de esta forma que es más sencillo que buscar su dirección:
#byte ANSEL = getenv ("SFR:ANSEL") // Nombre del registro.
Y sus bits correspondientes se pueden declarar a partir del mismo:
#bit BITX = ANSEL.X
Porque en el CCS no me deja declararlo como el programa de NUYEL, el cual está en otro compilador.
Pienso que al declararlo ¿Debería estar en forma de ensamblador?
Bueno, porque sí no, no me pueden funcionar bien los pines analógicos si los quiero utilizar como digitales.
La forma de declaración que mostré, es válida.
Pero también se pueden declarar los registros de ésta forma:
#byte PORTA = 0x05 // Dirección del registro
Y por defecto, el compilador de CCS (PCWHD) configura todo como digital al compilar.
 
ahh bien me han funcionado tus aportes, sin embargo al manipular usb-cdc solo veo ejemplos por polling
y trato de poner la #int_usb pero no me compila e investigado y hay una libreria para eso,pero al final no se como usarlo(es para comunicarme al labview por puerto serial para adquirir datos ) un ejemplo de referencia por fa
 
Buen día a todos los del foro , les comparto mi código fuente y el circuito de cruce por cero , estoy tratando de variar y con esto la idea es controlar el angulo de disparo del triac, pero al momento de variar el angulo de disparo que esta dentro del while no responde , si alguien pudiera hecharme una mano o idea se le agradeceria mucho.
C:
#include <xc.h>
#define _XTAL_FREQ 12000000
#include "CONFIG.h"
#define LED RD0

int T;
int angle;
//int estado;

//#define Pulso RB0


void interrupt inicio()
{
    if(INTF==1){
        
    T=(angle*16.6)/360;
    __delay_ms(T);
      LED=1;
    __delay_ms(1);
      LED=0;
  
     INTF=0;
    }
}

void main(void) {
    TRISD=0x00;
    PORTD=0;
    TRISB=0xFF;
    
    OPTION_REG=0b00000000;
    GIE=1;
    PEIE=1;
    INTE=1;
    
    //estado=0;
    //INTCONbits.GIE=1;
    //INTCONbits.INTE=1;
    //OPTION_REGbits.INTEDG=1;
    
    while(1)
    {
      angle=30;   
    }   
}

Aquí les muestro la imagen en proteus, el disparo se queda solo en ese punto mas no varía nose donde puede estar el error :unsure:.
Screenshot_1.png
 
No entiendo tu esquema.
¿Por qué está conectado el generador AC (VSIN) de esa forma?
¿Dónde está la carga para el TRIAC?
¿Por qué parece que existen dos generadores? (Lo que está detrás del osciloscopio)
¿Qué hay dentro de la librería faltante, "CONFIG.h"?

Se supone que debes sincronizar el pulso para el TRIAC con V2, no con otro generador.
¿Qué caso tiene que dentro del bucle principal la variable "angle" siempre tenga el mismo valor?
Aparte de lo mal del esquema... ¿Será por eso que nunca varía el ángulo del pulso?

Por eso siempre es mejor subir el proyecto completo dentro de un archivo comprimido.
Y también explicar más cómo es que pretendes que funcione el circuito de esa forma.
 
Hola Dark 🖐 toda observación es bienvenida y me sirve para poder mejorar y no cometer los mismos errores.
Al referirte de por qué esta conectado de esa forma el generador te refieres al 220VAC que esta al lado del triac? Esta mal conectado por qué?
La carga del triac le puse la resistencia de 10k o no puedo ponerle ese tipo de carga a un triac ?
El generador que está detrás del osciloscopio es la misma red de 220VAC que ingresa a un puente de diodos y luego a un optoacoplador (este es el circuito detector de cruce por cero ) . Este circuito lo vi en varios post y subido por Fogonazo , dime si puedo mejorar el circuito o quizás deba realizar otro circuito para el detector de cruce por cero.
La librería "CONFIG.h" es una cabecera, dentro de ésta se encuentra las configuraciones de los bits , lo añadí como librería para no tener muchas líneas de programa.
Al parecer esta mal que la variable "angle" vaya sólo dentro del while 🤔. Podrías sugerirme cómo podría mejorar todas las observaciones amigo Dark ?
 
Al referirte de por qué está conectado de esa forma el generador te refieres al 220VAC que esta al lado del triac? Esta mal conectado por qué?
Sí, a ese. Y está mal conectado porque debe haber un solo generador de CA.
Si la referencia de AC se toma de un transformador, no hay problema, pero en tu esquema existen dos fases.
Es más conveniente y simple usar un circuito con optoacopladores, uno para tomar la referencia del cruce por cero y otro para disparar el TRIAC, que en este caso sería un optotriac.
Para el de cruce por cero puedes usar una simple resistencia o un divisor de tensión para alimentar al LED.
Algo así:
Detector de cruce por cero media onda.PNG
El circuito de arriba es un detector de cruce por cero de media onda.

Detector de cruce por cero onda completa.PNG
El circuito de arriba es un detector de cruce por cero de onda completa.

Se debe tener en cuenta el tipo de detector a usar porque en el de onda completa se obtendrá el doble de pulsos que en el de media onda.
Y eso se debe tener en cuenta en el programa.

Y este otro es el que mencioné con transformador, también de onda completa:
Detector de cruce por cero con transformador.gif

La librería "CONFIG.h" es una cabecera, dentro de ésta se encuentra las configuraciones de los bits , lo añadí como librería para no tener muchas líneas de programa.
¿De cuáles bits? Si son los de la palabra de configuración únicamente te estás ahorrando una línea para ese PIC. (16F877A)
Al parecer está mal que la variable "angle" vaya sólo dentro del while 🤔. Podrías sugerirme cómo podría mejorar todas las observaciones amigo Dark ?
Está mal si siempre mantiene el mismo valor, o sea: angle = 30;
Por eso te dije que estando con un valor fijo, no tiene sentido que esté dentro del bucle principal.
Y es que mencionas que angle no cambia, obviamente no cambiará porque tiene un valor fijo en 30.
Si esta variable fuera modificada por pulsadores, un potenciómetro u otra cosa, pues sí que debería estar ahí.

Edit:
En dado caso que yo quisiera tratar de compilar tu programa y ver lo que hace, tendría que cambiar algunas cosas.
Ya que por la sintaxis que veo para el servicio de interrupciones, estás usando una versión vieja de XC8
El __delay_ms(); ahora ya no permite variables como parámetro.
Y es que en las versiones actuales han cambiado muchas cosas, y si tratara de compilarlo seguramente obtendría errores.
 
Hola de nuevo Dark, gracias por la sugerencia de los esquemas, están interesantes, veo que en proteus funcionan solo faltaría implementar con todo el PIC .
Con respecto al compilador XC8 (Uso MPLAB como entorno de desarrollo)es una versión actual ya que lo volví a descargar desde la página de Microchip hace 1 mes , es la versión actualizada que está en su página oficial. Para el uso de interrupciones puedo escribirlo por ejemplo como INTCONbits.GIE=1 asi como GIE=1 igual me lo permite así como colocar dentro del __delay_ms () una variable.
Que versión de compilador usas ? Usas MPLAB para programar en C ? 🤔
 
Atrás
Arriba