Inhaltsverzeichnis

Zum Erstellen von Programmen für den PIC12F629 (und auch diverse andere Mikroprozessoren) verwendet man am besten die MPLAB X IDE (http://www.microchip.com/). Für die C Programmiersprache muss man noch den XC8 (für 8 bit prozessoren) Compiler installieren.

Mit der MPLAB X IDE installiert sich auch die MPLAB X IPE Applikation, mit der man fertige HEX Dateien auch ohne IDE auf den Mikroprozessor brennen kann.

PIC12F629 LED blinken

Im folgenden ein ganz einfaches Beispiel für die Verwendung eines PIC12F629. Am PIN 7 (GP0) wird eine LED angehängt. PIN 8 (GND) wird mit Masse (= minuspol des Netzgerätes) verbunden und an PIN 1 (VDD) werden die 3V Gleichspannung angelegt.

Programmierung in C

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
 
#define _XTAL_FREQ 4000000 // Oscillator frequency for _delay()
#define __delay_ms(x) _delay((unsigned long) ((x)*(_XTAL_FREQ/4000.0)))
 
//Config: int reset, no code protect, no brownout detect, no watchdog,
//        power-up timer enabled, 4MHz internal clock
 
#pragma config WDTE = OFF, PWRTE = ON, CP = OFF, BOREN = OFF, MCLRE = OFF, CPD = OFF, FOSC = INTRCCLK
 
void main()
{
   GPIO =   0;
   CMCON =  0b11111111;
   TRISIO = 0b11111110; //output to GP0
 
   GPIObits.GP0 = 1;
 
   for(;;)
   {
      GPIObits.GP0 = 1;
      __delay_ms(200);
      GPIObits.GP0 = 0;
      __delay_ms(200);
   }
}

Programmierung in Assembler

Bei der Programmierung in Assembler gibt es zwei Möglichkeiten:

absolute code

Dies bedeutet, dass man beim Codieren die Speicheraddressen selber festlegt. Dies sieht etwa so aus:

   myVar equ 0x20 ; myVar zeigt auf Speicheraddresse 0x20
 
   org 0x0000 ; ab hier code
 
main
  ; machwas
end

Bei Verwendung der MPLAB X IDE allerdings sieht man im Debug-Modus diese Variablen nicht, das dürfte auch daran liegen, dass MLINK für die Erstellung des Maschinencodes verwendet wird.

relocatable code

In diesem Fall übernimmt die Arbeit der Speicherzuordnung von Variablen etc. der Linker.

   UDATA_SHR   ; UDATA alleine führt zu einem Linker error
   myVar res 1 ; reserviere 1 Byte für myVar
 
   RESET CODE 0x000 ; ab hier code
 
main
  ;machwas
end   

Vorteil dieser Methode ist, dass sich dieser Code dann besser in der MPLAB X IDE debuggen lässt, da man jetzt alle Variablen sieht.

LED blinken, interner Timer

Einer der Vorteile des C Programmiersprache sind die vielen fertigen Libraries die Funktionen wie zb. _delay_ms() zur Verfügung stellen. Für das Abwarten des Zeitraumes X in Assembler muss man selber geeignete Routinen implementieren. Dies kann im einfachsten Fall eine Schleife sein, die x-mal NOP (= no operation) ausführt.

Im folgenden Beispiel wird der TIMER0 des PIC Prozessors verwendet. Der PIC12F629 läuft mit 4 MHz. Der Timer wird über den Prescaler an den internen Takt angeschlossen. Der TIMER0 ist limitiert auf 8 bit und zählt daher nur bis max. 255. Eine weitere Einschränkung ist, dass der Timer auf 1/4 der Taktfrequenz limitiert ist d.h. dieser läuft nur mit 1 MHz. Wenn man den Prescaler auf das Verhältnis 1:32 setzt, bedeutet dies dass der Timer0 alle 32 µs einen Impuls/Tick erhält und um eins hochgezählt wird. Ein Wert von 250 im TIMER0 entspricht dann etwa 8 ms.

;---------------------------------------------------------
;22.07.2014 Stelzl Marius
;translate from C to ASM
    list      P=12F629		        ; Prozessor definieren
    include "P12F629.inc"		; entsprechende .inc Datei für MPASM
 
;#pragma config WDTE = OFF, PWRTE = ON, CP = OFF, BOREN = OFF, 
;  MCLRE = OFF, CPD = OFF, FOSC = INTRCCLK
__config _WDTE_OFF & _PWRTE_ON & _CP_OFF & _BOREN_OFF & 
   _MCLRE_OFF & _CPD_OFF & _FOSC_INTRCCLK
 
;variable definition
;relocatable, use udata_shr
    UDATA_SHR
counter1 res 1 ;reserve one byte for counter1 variable
counter2 res 1 ;wait counter
 
;-----------------------------------------------------------------
;code starts here
RESET CODE 0x000
 
    goto main
 
;------------------------------------------------------------------
;init subroutine
init
    bcf  STATUS,RP0    ;select bank 0
    clrf GPIO          ;GPIO = 0;
 
    movlw 0xFF         ;CMCON =  0b1111111;
    movwf CMCON        ;set all GPIO to digital IO
 
    bsf  STATUS,RP0    ;select bank1
 
    ;setting TRISIO bit
    ; 1 ... PIN is input
    ; 0 ... PIN is output
    movlw 0xFE         ;0xFE = 254 = 0b11111110
    movwf TRISIO       ;TRISIO = 0b1111110; //output to GP0
 
    ; OPTION register is also on bank1
    ; setup for usage of Timer0 with prescale 1:32
    movlw b'11010100'
    movwf OPTION_REG
 
    return
 
;--------------------------------------------
;wait routine
wait_500
        clrf counter2
waitls  clrf TMR0
 
w_tmr0  movf TMR0,w
        xorlw .250      ;250 ticks x 32 us/tick = 8ms
        btfss STATUS,Z
        goto w_tmr0
 
        incf counter2,1
        movlw .63        ;passed 62 * 8 ms = 500 ms ?
        xorwf counter2,0
        btfss STATUS,Z
        goto waitls
 
    return
 
;--------------------------------------------
;our processing starts here
main 
    clrf  counter1
    movlw 0x2
    movwf counter1
loop
    decfsz counter1,1 ;we call the init subproc only once
    call init
 
    bcf STATUS,RP0    ;select bank 0 for writing to GPIO
    bsf GPIO,0        ;set bit 0 of GPIO register to 1 => GPIObits.GP0 = 1;
 
    ;wait 500 ms
    call wait_500
    ;now switch off LED
    bcf GPIO,0       ;clear bit 0 of GPIO register
    call wait_500
 
    goto loop        ;endless loop, run forever
 
    end