Tuesday, May 24, 2011

Controlling a nokia5110 lcd with software SPI on a pic16f84a




My newest project has been implementing a software SPI routine so that my pic (which lacks hardware SPI) can communicate with a cheap nokia 84x48 graphical lcd (later I will show how I wired it up). I've written subroutines in assembly for setting x,y address of the lcd's ram as well as sending data or commands for initialization (8bit, but could be easily modified to work with 9bit color lcd protocols I've seen). I plan on using a look up table to store standard character hex data so that I can make things easier for myself in upcoming projects. I know that my code is pretty inefficient so I plan on fixing it a little later (but not bad for just reading the datasheet and a few hours of coding). I just have the mcu writing "Hello World!" and drawing a video game character sprite at the bottom (I converted the image by hand, but I could easily write a program to do that for me). This is just the beginning, I plan on using this, as well as everything else I've been working on in my projects to come. I plan on adding the ability to animate/scroll text and images and will update the site with the code once I get the chance. I also plan on describing the SPI protocol and lcd commands in detail. For now I will post the code to just write "Hello World" and draw a sprite.

Start    BSF  03h,5         ;switch from bank 0 to 1

    MOVLW  b'00000000' ;Out RB to output
    MOVWF 06h
    MOVLW  b'00000'       ;Out RA to output
    MOVWF 05h

    BCF 03h,5          ;switch from bank 1 to 0     
;RB0=sclk
;RB1=sda
;RB2=D_C
;RB3=Sce
;RB4=reset
;RB5=disp pwr
Begin
    bsf 06h,3 ;disable serial
    bsf 06h,5 ;power on display
    nop
    bcf 06h,4 ;reset
    nop
    bsf 06h,4 ;release from reset

; sel extended instruction set (h=1)
    movlw b'00100001'
    movwf 0Ch
    call spi_command

; set Vop (Contrast)
    movlw b'10111001'
    movwf 0Ch
    call spi_command

; sel normal instruction set (h=0)
    movlw b'00100000'
    movwf 0Ch
    call spi_command

; display normal mode
    movlw b'00001100'
    movwf 0Ch
    call spi_command

;---------------------------

; draw H
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data

call _space

; draw e
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010101'
    movwf 0Ch
    call spi_data
    movlw b'00010101'
    movwf 0Ch
    call spi_data
    movlw b'00010101'
    movwf 0Ch
    call spi_data
    movlw b'00001100'
    movwf 0Ch
    call spi_data

call _space

; draw l
    movlw b'00000000'
    movwf 0Ch
    call spi_data
    movlw b'01000001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00000000'
    movwf 0Ch
    call spi_data

call _space

; draw l
    movlw b'00000000'
    movwf 0Ch
    call spi_data
    movlw b'01000001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00000000'
    movwf 0Ch
    call spi_data

call _space

; draw o
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00001110'
    movwf 0Ch
    call spi_data

call _space

; goto y=1,x=0
    movlw b'00000001'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy

; draw W
    movlw b'01111110'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'01111110'
    movwf 0Ch
    call spi_data

call _space

; draw o
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00001110'
    movwf 0Ch
    call spi_data

call _space

; draw r
    movlw b'00011111'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data
    movlw b'00010000'
    movwf 0Ch
    call spi_data
    movlw b'00010000'
    movwf 0Ch
    call spi_data
    movlw b'00001000'
    movwf 0Ch
    call spi_data

call _space

; draw l
    movlw b'00000000'
    movwf 0Ch
    call spi_data
    movlw b'01000001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data
    movlw b'00000001'
    movwf 0Ch
    call spi_data
    movlw b'00000000'
    movwf 0Ch
    call spi_data

call _space

; draw d
    movlw b'00001110'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00010001'
    movwf 0Ch
    call spi_data
    movlw b'00001001'
    movwf 0Ch
    call spi_data
    movlw b'01111111'
    movwf 0Ch
    call spi_data

call _space

; draw !
    movlw b'01111101'
    movwf 0Ch
    call spi_data

;---------------------------
; goto y=5,x=0
    movlw b'00000101'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy
;draw image block 4
    movlw b'10000111';1
    movwf 0Ch
    call spi_data
    movlw b'11111101';2
    movwf 0Ch
    call spi_data
    movlw b'10000001';3
    movwf 0Ch
    call spi_data
    movlw b'01100001';4
    movwf 0Ch
    call spi_data
    movlw b'00010001';5
    movwf 0Ch
    call spi_data
    movlw b'11001001';6
    movwf 0Ch
    call spi_data
    movlw b'00100101';7
    movwf 0Ch
    call spi_data
    movlw b'00100101';8
    movwf 0Ch
    call spi_data
    movlw b'11100001';9
    movwf 0Ch
    call spi_data
    movlw b'00011001';10
    movwf 0Ch
    call spi_data
    movlw b'00000101';11
    movwf 0Ch
    call spi_data
    movlw b'00000011';12
    movwf 0Ch
    call spi_data
    movlw b'00000011';13
    movwf 0Ch
    call spi_data
    movlw b'00000001';14
    movwf 0Ch
    call spi_data
    movlw b'00111001';15
    movwf 0Ch
    call spi_data
    movlw b'11101101';16
    movwf 0Ch
    call spi_data
    movlw b'00000111';17
    movwf 0Ch
    call spi_data

; goto y=4,x=0
    movlw b'00000100'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy
;draw image block 3
    movlw b'00000111';1
    movwf 0Ch
    call spi_data
    movlw b'00111100';2
    movwf 0Ch
    call spi_data
    movlw b'01100100';3
    movwf 0Ch
    call spi_data
    movlw b'01010011';4
    movwf 0Ch
    call spi_data
    movlw b'11110000';5
    movwf 0Ch
    call spi_data
    movlw b'00111000';6
    movwf 0Ch
    call spi_data
    movlw b'11111001';7
    movwf 0Ch
    call spi_data
    movlw b'11111011';8
    movwf 0Ch
    call spi_data
    movlw b'10010011';9
    movwf 0Ch
    call spi_data
    movlw b'11110100';10
    movwf 0Ch
    call spi_data
    movlw b'11110100';11
    movwf 0Ch
    call spi_data
    movlw b'01110100';12
    movwf 0Ch
    call spi_data
    movlw b'01110000';13
    movwf 0Ch
    call spi_data
    movlw b'00010000';14
    movwf 0Ch
    call spi_data
    movlw b'00100100';15
    movwf 0Ch
    call spi_data
    movlw b'10011111';16
    movwf 0Ch
    call spi_data
    movlw b'11010000';17
    movwf 0Ch
    call spi_data
    movlw b'01110000';18
    movwf 0Ch
    call spi_data

; goto y=3,x=0
    movlw b'00000011'
    movwf 0Ch
    movlw b'00000000'
    movwf 0Dh
    call setxy
;draw image block 2
    movlw b'00011100';1
    movwf 0Ch
    call spi_data
    movlw b'00010110';2
    movwf 0Ch
    call spi_data
    movlw b'00010010';3
    movwf 0Ch
    call spi_data
    movlw b'00010010';4
    movwf 0Ch
    call spi_data
    movlw b'00010011';5
    movwf 0Ch
    call spi_data
    movlw b'00010001';6
    movwf 0Ch
    call spi_data
    movlw b'00110001';7
    movwf 0Ch
    call spi_data
    movlw b'00100000';8
    movwf 0Ch
    call spi_data
    movlw b'01100000';9
    movwf 0Ch
    call spi_data
    movlw b'01000000';10
    movwf 0Ch
    call spi_data
    movlw b'11000000';11
    movwf 0Ch
    call spi_data
    movlw b'10000000';12
    movwf 0Ch
    call spi_data
    movlw b'00000000';13
    movwf 0Ch
    call spi_data
    movlw b'00000010';14
    movwf 0Ch
    call spi_data
    movlw b'00011111';15
    movwf 0Ch
    call spi_data
    movlw b'01110001';16
    movwf 0Ch
    call spi_data
    movlw b'11000000';17
    movwf 0Ch
    call spi_data

; goto y=2,x=12
    movlw b'00000010'
    movwf 0Ch
    movlw b'00001100'
    movwf 0Dh
    call setxy
;draw image block 1
    movlw b'00000001';12
    movwf 0Ch
    call spi_data
    movlw b'00000001';13
    movwf 0Ch
    call spi_data
    movlw b'00000011';14
    movwf 0Ch
    call spi_data
    movlw b'00000010';15
    movwf 0Ch
    call spi_data
    movlw b'00000010';16
    movwf 0Ch
    call spi_data
    movlw b'00000011';17
    movwf 0Ch
    call spi_data

a goto a

;----------------------------

spi_command
    bcf 06h,3 ;start serial transmission
    bcf 06h,2 ;D_C=0
        btfss 0Ch,7
        goto c1
        call one
        goto c1n
    c1    call zero
    c1n    btfss 0Ch,6
        goto c2
        call one
        goto c2n
    c2    call zero
    c2n    btfss 0Ch,5
        goto c3
        call one
        goto c3n
    c3    call zero
    c3n    btfss 0Ch,4
        goto c4
        call one
        goto c4n
    c4    call zero
    c4n    btfss 0Ch,3
        goto c5
        call one
        goto c5n
    c5    call zero
    c5n    btfss 0Ch,2
        goto c6
        call one
        goto c6n
    c6    call zero
    c6n    btfss 0Ch,1
        goto c7
        call one
        goto c7n
    c7    call zero
    c7n    btfss 0Ch,0
        goto cd
        call one
        goto cdn
    cd    call zero
cdn    bcf 06h,0
    bsf 06h,3 ;end serial transmission
return

spi_data
    bcf 06h,3 ;start serial transmission
    bsf 06h,2 ;D_C=1
        btfss 0Ch,0
        goto b1
        call one
        goto b1n
    b1    call zero
    b1n    btfss 0Ch,1
        goto b2
        call one
        goto b2n
    b2    call zero
    b2n    btfss 0Ch,2
        goto b3
        call one
        goto b3n
    b3    call zero
    b3n    btfss 0Ch,3
        goto b4
        call one
        goto b4n
    b4    call zero
    b4n    btfss 0Ch,4
        goto b5
        call one
        goto b5n
    b5    call zero
    b5n    btfss 0Ch,5
        goto b6
        call one
        goto b6n
    b6    call zero
    b6n    btfss 0Ch,6
        goto b7
        call one
        goto b7n
    b7    call zero
    b7n    btfss 0Ch,7
        goto d
        call one
        goto dn
    d    call zero
dn    bcf 06h,0
    bsf 06h,3 ;end serial transmission
return

zero
    bcf 06h,0
    bcf 06h,1 ;0
    bsf 06h,0 ;sclk pulse
return

one
    bcf 06h,0
    bsf 06h,1 ;1
    bsf 06h,0 ;sclk pulse
return

_space ;send byte='00000000', draw space
    movlw b'00000000'
    movwf 0Ch
    call spi_data
return

setxy
    bsf 0Ch,6
    call spi_command
    bsf 0Dh,7
    movf 0Dh,0
    movwf 0Ch
    call spi_command
return

end

Tuesday, May 10, 2011

Capacitive Touch Sensor for pic16F84A (no special hardware required)

Here is my newest project I've been working on. I'll get more details up when I have the time. In the mean while enjoy the video.

 
Update: Sorry its been awhile since my last update. I've been busy with work and my other projects. The capacitive sensing input is really simple because everything is done in software. Here's my hand drawn schematic for the input stage generalized so that any mcu can be used (For some reason I haven't yet installed a schematic program on my netbook and I don't feel like booting up my other laptop).
It's amazing that all you really need is a single gpio and a resistor (the capacitance is provided by the traces on the breadboard). The ten megaohm resistor allows the discharge rate for the stray capacitance to be slowed down enough for the uC to measure. The uC just continually charges up this capacitance, puts the pin into high impedance by making it an input, and then counts until it measures the "capacitor" is discharged. This count can then be analyzed to determine if the pin has been pressed or not (the count increases if the button is pressed because your finger adds to the stray capacitance in parallel which increases the discharge time). That's pretty much all that's necessary other than some fancy algorithms for error proofing detection.

Update 2: I've finally gotten around to porting my capacitive touch sensing code to C. The code should work for most PICs and can be easily modified to change pin assignments and whatnot to work on any other chip you might need. Below you will find the function freqcapsense. All you need to do is call it and it will sense whether RA0 is being touch or not. I've included averaging multiple samples and an adjustable threshold in order to tweak the sensitivity and accuracy for any given setup. You can have it return a 1 or 0 for touch status or by commenting out the if else statement at the end and uncommenting the return current statement it will return the raw period value it is reading from the pin. Enjoy.

int freqcapsense(){
    unsigned int avg;
    unsigned int current=0;
    unsigned int thresh=29;
    unsigned int trials=10;

    while(trials>0){
        TRISA=0b0;
        RA0=1;
        delay();
        TRISA=0b1;
        while(RA0==1){current++;}
        trials--;
        avg=(avg+current)/2;
    }

    if((current-avg)>thresh){return 1;}
    else{return 0;}

    //return current;
}