Continue to Site

Noob pic16f18324 programming SPI

Lithium Grim

Newbie
Newbie level 1
Joined
Feb 23, 2025
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
37
So, I am starting my journey with programming pic controllers. Currently using MPLAN X IDE v6.05/XC8 to program a pic 16f18324 (master) and control a MCP411000 (slave) to change it's resistance value. My code up till now is:

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <xc.h>
 
 
// CONFIG1 - Gebruik interne oscillator
#pragma config FEXTOSC = OFF    // Geen externe klok
#pragma config RSTOSC = HFINT32 // Start met 32 MHz interne oscillator
#pragma config CLKOUTEN = OFF   // Clock output uitgeschakeld
#pragma config CSWEN = ON       // Clock switch toegestaan
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor uitgeschakeld
 
 
// CONFIG2
#pragma config MCLRE = ON       // MCLR pin ingeschakeld
#pragma config PWRTE = OFF      // Power-up Timer uitgeschakeld
#pragma config WDTE = OFF       // Watchdog Timer uitgeschakeld
#pragma config BOREN = ON       // Brown-out Reset ingeschakeld
#pragma config BORV = LOW       // Brown-out Reset Voltage = 2.45V
#pragma config PPS1WAY = ON     // PPS kan slechts één keer worden gewijzigd
#pragma config STVREN = ON      // Stack Overflow Reset ingeschakeld
#pragma config DEBUG = OFF      // Debugging uitgeschakeld
 
 
// CONFIG3
#pragma config WRT = OFF        // Flash-geheugen niet schrijfbeveiligd
#pragma config LVP = OFF        // Low-Voltage Programming UIT
 
 
// CONFIG4
#pragma config CP = OFF         // Code Protectie uitgeschakeld
#pragma config CPD = OFF        // Data NVM Protectie uitgeschakeld
 
 
#define _XTAL_FREQ 32000000  // 32 MHz internal oscillator
 
 
#define CS LATCbits.LATC2  // Chip Select op RC2 (Pin 8)
 
 
void SPI_Init(void) {
    // SPI-poorten instellen
    TRISCbits.TRISC3 = 0;  // SCK as output (MCP41100 Pin 2)
    TRISCbits.TRISC5 = 0;  // SDO as output (MCP41100 Pin 3)
    TRISCbits.TRISC2 = 0;  // CS as output (MCP41100 Pin 1)
 
 
    // Peripheral Pin Select (PPS) instellen
    SSP1CLKPPS = 0x07;  // SCK1 input op RC3 (MCP41100 Pin 2)
    RC3PPS = 0x16;      // SCK1 output op RC3
    RC5PPS = 0x14;      // SDO1 output op RC5 (MCP41100 Pin 3)
 
 
    // SPI module instellen (Master mode, SPI mode 0,0)
    SSP1CON1 = 0b00100010;  // SPI Master mode, clock = Fosc/64
    SSP1STAT = 0b00000000;  // Data sample in middle, clock idle low (Mode 0,0)
   
    CS = 1;  // CS hoog houden als standaard
}
 
 
void Timer2_Init(void) {
    T2CONbits.T2CKPS = 0b10;  // Prescaler = 1:16
    T2CONbits.T2OUTPS = 0b0000;  // Postscaler = 1:1
    PR2 = 49;  // 0,1 ms (100 µs) per interrupt
    TMR2 = 0;  // Reset Timer2
    PIR1bits.TMR2IF = 0;  // Clear interrupt flag
    PIE1bits.TMR2IE = 1;  // Enable Timer2 interrupt
    T2CONbits.TMR2ON = 1; // Start Timer2
    INTCONbits.PEIE = 1;  // Enable Peripheral Interrupts
    INTCONbits.GIE = 1;   // Enable Global Interrupts
}
 
 
void __interrupt() ISR(void) {
    if (PIR1bits.TMR2IF) {
        PIR1bits.TMR2IF = 0;  // Reset interrupt flag
        //To do: other functionality :)
    }
}
 
 
void SPI_Write(unsigned char data) {
    CS = 0;  // Chip Select laag om communicatie te starten
    SSP1BUF = data;  // Data in buffer laden
    while (!SSP1STATbits.BF);  // Wachten tot transmissie klaar is
    CS = 1;  // Chip Select hoog zetten om communicatie te beëindigen
}
 
 
void MCP41100_SetResistance(unsigned char value) {
    SPI_Write(0b00010001);  // Write to Wiper Register
    SPI_Write(value);        // New value (0x00-0xFF)
}
 
 
void main(void) {
    // Internal oscillator at 32 MHz
    OSCFRQ = 0x06; 
    OSCCON1 = 0x60;
 
    SPI_Init();    // SPI initialiseren
    Timer2_Init(); // Timer2 starten voor 1 ms timing
 
    while (1) {
        MCP41100_SetResistance(0x80);  // instellen (50%)
        __delay_ms(1000);
 
        MCP41100_SetResistance(0xFF);  // Maximale weerstand
        __delay_ms(1000);
 
        MCP41100_SetResistance(0x00);  // Minimale weerstand
        __delay_ms(1000);
    }
}


I cannot get this simple test (50%, 0% and 100% resistor value) to work.

I am trying to use RC3 = SCK/clock, RC5 = SDO/dataoutput and RC2 = CS. Can anyone help me on my way?

On the MPC4110 pin 1 = CS, pin2=SCK pin3 = SI
 
Last edited by a moderator:
Hi,

I miss the SS_n handling.

It should be HIGH on idle,
LOW before communication
HIGH after (block) communication is finished.

Klaus
 
Not answering your question but a couple of comments on your code.
Firstly, put the "#include <xc.h>" after the config pragmas. This is the way that the MPLABx recommends and also gets around any possible later issues with redefining "ON" and "OFF" (not that you are here bit it is a VERY common source of had to trace problems).
Don't set the DEBUG pragma. This is controlled by the MPLAB IDE when you select a release or debug build. Also the debug builds do more than just set this config setting that just setting this does not do.

Now to your question: please look at Figure 5-1 of the datasheet (https://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf) and compare the \CS\ line with how you are controlling it in your SPI_Write() function. In the data sheet it shows the \CS| line being low for both the command and data bytes whereas you only have it low for each byte. What that will do is to to cancel the command and possibly try to interpret the data byte as a command but it wil then get cancelled anyway.
Move the 'CS=0' and 'CS=1' lines into your MCP411200_SetResistance() function

Can I suggest that you don't use the 'magic numbers' for registers such as SSP21CON1 and SSP1STAT. You are using the register bit references elsewhere and this makes it much easier to not only write in the first place but for you and others to read later on.
Personally I would NOT set the interrupt enable bits (PEIE and GIE) within the timer initialisation function. Instead, do all of the setup and then enable the interrupts. While you only have the interrupts in one place now, when you later have a more complex progam and you try to 'cut and paste' code from previous programs, turning on the global interrupts too soon can cause problems. Moving the enable code into the main setup section is good practice.

Susan

PS: I see that @KlausST mentioned the \CS\ handling while I was typing.
 


Write your reply...

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top