i'm currently trying to use a button as an interrupt. But i'm struggling with it. I've seen in the datasheet that i should enable: INTE bit of PIE0, INTEDG of INTCON, AND GIE if PIE.
I've also seen that i have to use the INTPPS register to configure a pin to be the interrupt, so as i want to use RB0 as an interupt, then i used PIR0bits.INTF to check if the interupt= true in my ISR. I did that :
void ledLoop(unsigned char *ptr){
unsigned char *tmp = ptr;
while(*tmp<64){
LATB = *tmp;
*tmp *= 2;
__delay_ms(200);
}
}
void __interrupt() high_isr(void){
INTCONbits.GIE = 0;
if( PIR0bits.INTF){
LATB = ~LATB;
PIR0bits.INTF = 0;
}
INTCONbits.GIE = 1;
}
void launch(void){
unsigned char run = 1;
while(1){
if(PORTDbits.RD7==1){
unsigned char tmp = 1;
ledLoop(&tmp);
}
if(PORTDbits.RD6==1){
LATB=0xff;
}
else{
LATB=0;
}
}
}
void main(void)
{
ANSELDbits.ANSD7=0;
ANSELDbits.ANSD6=0;
TRISB=0;
TRISA=0;
LATA=0x00;
TRISDbits.TRISD7=1;
TRISDbits.TRISD6=1;
TRISBbits.TRISB0=1;
//GIE: Global Interrupt Enable bit
//PEIE: Peripheral Interrupt Enable bit
PIE0bits.INTE = 1;
INTCONbits.GIE = 1;
INTCONbits.INTEDG = 1;
INTPPSbits.INTPPS = 0x08;
launch();
}
Any idea of what is wrong ?
using :
MPLABX IDE
XC8 Compiler
PIC16F18875
There are three thing wrong with the code you posted:
No configuration words, so code will not build as posted
Changing the GIE bit inside of an ISR
PORTB pin RB0 not configured for digital input
See my comments using /* */ for your code fixed:
/*
* File: main.c
* Author: dan1138
*
* Created on September 24, 2020, 2:23 PM
*/
// PIC16F18875 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1
#pragma config FEXTOSC = OFF // External Oscillator mode selection bits (Oscillator not enabled)
#pragma config RSTOSC = HFINT32 // Power-up default value for COSC bits (HFINTOSC with OSCFRQ= 32 MHz and CDIV = 1:1) (FOSC = 32 MHz))
#pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
#pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)
// CONFIG2
#pragma config MCLRE = ON // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config LPBOREN = OFF // Low-Power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = OFF // Brown-out reset enable bits (Brown-out reset disabled)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
#pragma config ZCD = OFF // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = OFF // Peripheral Pin Select one-way control (The PPSLOCK bit can be set and cleared repeatedly by software)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)
// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF // WDT operating mode (WDT Disabled, SWDTEN is ignored)
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC // WDT input clock selector (Software Control)
// CONFIG4
#pragma config WRT = OFF // UserNVM self-write protection bits (Write protection off)
#pragma config SCANE = available// Scanner Enable bit (Scanner module is available for use)
#pragma config LVP = ON // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)
// CONFIG5
#pragma config CP = OFF // UserNVM Program memory code protection bit (Program Memory code protection disabled)
#pragma config CPD = OFF // DataNVM code protection bit (Data EEPROM code protection disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#define _XTAL_FREQ (32000000ul)
void ledLoop(unsigned char *ptr){
unsigned char *tmp = ptr;
while(*tmp<64){
LATB = *tmp;
*tmp *= 2;
__delay_ms(200);
}
}
void __interrupt() high_isr(void){
//INTCONbits.GIE = 0; /* <= do not do this in an interrupt service routine */
if((PIE0bits.INTE) && ( PIR0bits.INTF)){ /* check that the interrupt is enabled AND asserted */
LATB = ~LATB;
PIR0bits.INTF = 0;
}
//INTCONbits.GIE = 1; /* <= do not do this in an interrupt service routine */
}
void launch(void){
unsigned char run = 1;
while(1){
if(PORTDbits.RD7==1){
unsigned char tmp = 1;
ledLoop(&tmp);
}
if(PORTDbits.RD6==1){
LATB=0xff;
}
else{
LATB=0;
}
}
}
void main(void)
{
ANSELDbits.ANSD7=0;
ANSELDbits.ANSD6=0;
TRISB=0;
TRISA=0;
LATA=0x00;
TRISDbits.TRISD7=1;
TRISDbits.TRISD6=1;
TRISBbits.TRISB0=1;
ANSELBbits.ANSB0=0; /* make RB0 a digital input */
//GIE: Global Interrupt Enable bit
//PEIE: Peripheral Interrupt Enable bit
PIE0bits.INTE = 1;
INTCONbits.GIE = 1;
INTCONbits.INTEDG = 1;
INTPPSbits.INTPPS = 0x08; /* assign INT input to RB0 */
launch();
}
Related
HI I'm trying to implement simple spi communication to turn on 8 led connected to shift register can amy one help me whats wrong with this code, im getting random output, I want to send 0x02 to turn on led(00000010) .
#include <xc.h>
#include "spi.h"
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage In-Circuit Serial Programming Enable bit
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit
#pragma config WRT = OFF // Flash Program Memory Write Enable bits
#pragma config CP = OFF // Flash Program Memory Code Protection bit
#define _XTAL_FREQ 8000000
void main()
{
char data = 0x10;
spiInit(SPI_MASTER_OSC_DIV4, SPI_DATA_SAMPLE_END, SPI_CLOCK_IDLE_LOW, SPI_IDLE_2_ACTIVE);
TRISC0 = 0;
RC0 = 1;
RC3 = 0;
RC5 = 0;
while(1)
{
RC0 = 0; //Slave Select
__delay_ms(100);
spiWrite(data);
while(!SSPSTATbits.BF);
__delay_ms(100);
RC0= 1; //Slave Deselect
}
}
I have been studying microcontrollers so far and I gone through LCD and understood how it worked in 8 bits mode but 1 thing I don't understand is how to work with it in 4 bits mode and whatever I try in code I cant ever make it and I searched almost all the sites available on the internet to explain this topic but still didn't get it so I would very much appreciate if someone could spend some of his time explaining this to me thanks in advance.
#user3674628: By now you must have had known how to interface in 4-bit modes. Though you didnt specify the compiler you use here is an example I have been using with mplabx with xC8 compiler. It works pretty well. Do not forget to adjust the configuration bits on mplabx. Success!
// PIC18F4550 Configuration Bit Settings
// 'C' source line config statements
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1L
#pragma config PLLDIV = 5
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2
// CONFIG1H
#pragma config FOSC = INTOSCIO_EC //this uses internal oscillator
#pragma config FCMEN = OFF
#pragma config IESO = OFF
// CONFIG2L
#pragma config PWRT = OFF
#pragma config BOR = OFF
#pragma config BORV = 3
#pragma config VREGEN = OFF
// CONFIG2H
#pragma config WDT = OFF
#pragma config WDTPS = 32768
// CONFIG3H
#pragma config CCP2MX = ON
#pragma config PBADEN = OFF
#pragma config LPT1OSC = OFF
#pragma config MCLRE = OFF
// CONFIG4L
#pragma config STVREN = ON
#pragma config LVP = OFF
#include <p18f4550.h>
#include <stdio.h>
#include <stdlib.h>
#include <plib/xlcd.h>
/* DATA_PORT defines the port to which the LCD data lines are connected */
#define DATA_PORT PORTB //for 4-bit mode connect D4-D7 of lcd to B0-B3 of lcd
#define TRIS_DATA_PORT TRISB
/* This defines the port where the control lines are connected.
* These are just samples, change to match your application.
* you may omit this part because its in y the compiler.
*/
#define RW_PIN LATBbits.LATB6
#define TRIS_RW TRISBbits.TRISB6
#define RS_PIN LATBbits.LATB5
#define TRIS_RS TRISBbits.TRISB5
#define E_PIN LATBbits.LATB4
#define TRIS_E TRISBbits.TRISB4
#define _XTAL_FREQ 4000000 // SET THIS TO SUIT YOUR FREQUENCY
void Wait(unsigned int delay)//delay for 100ms
{
for(;delay;delay--)
__delay_us(100);
}
//initialise the lcd
void LCDInit(){
OpenXLCD(FOUR_BIT & LINES_5X7 & CURSOR_ON & BLINK_OFF);
while(BusyXLCD());
WriteCmdXLCD(SHIFT_DISP_LEFT);
while(BusyXLCD());
}
void main(void)
{
ADCON1 = 0xF; // No analog, all digital i/o
TRISB = 0x0;
LCDInit()//initialise lcd
putrsXLCD( " Thanks God" );//display on the lcd
while(BusyXLCD());
WriteCmdXLCD(0xC0);// go to the next line on the lcd
while(BusyXLCD());
putrsXLCD( " I made it" );//display on the lcd
while(BusyXLCD());
while(1);
}
void DelayFor18TCY(void){
Delay10TCYx(20);
}
void DelayPORXLCD(void){
Delay1KTCYx(30);
}
void DelayXLCD(void){
Delay1KTCYx(10);
}
Have you tried these?
http://learningmsp430.wordpress.com/2013/11/16/16x2-lcd-interfacing-in-4-bit-mode/
http://www.spickles.org/projects/4-bit-lcd/
The first is pretty informative, and the second has example source code.
For 4-bit interface data, only four bus lines (DB4 to DB7) are used for transfer. Bus lines DB0 to DB3
are disabled. The data transfer between the HD44780U and the MPU is completed after the 4-bit data
has been transferred twice. As for the order of data transfer, the four high order bits (for 8-bit
operation, DB4 to DB7) are transferred before the four low order bits (for 8-bit operation, DB0 to
DB3).
The busy flag must be checked (one instruction) after the 4-bit data has been transferred twice. Two
more 4-bit operations then transfer the busy flag and address counter data.
For 8-bit interface data, all eight bus lines (DB0 to DB7) are used.
Here is an example on how it works:
#include <msp430g2553.h>
#define DR P1OUT = P1OUT | BIT4 // define RS high
#define CWR P1OUT = P1OUT & (~BIT4) // define RS low
#define READ P1OUT = P1OUT | BIT5 // define Read signal R/W = 1 for reading
#define WRITE P1OUT = P1OUT & (~BIT5) // define Write signal R/W = 0 for writing
#define ENABLE_HIGH P1OUT = P1OUT | BIT6 // define Enable high signal
#define ENABLE_LOW P1OUT = P1OUT & (~BIT6) // define Enable Low signal
void data_write(void)
{
ENABLE_HIGH;
delay(2);
ENABLE_LOW;
}
void data_read(void)
{
ENABLE_LOW;
delay(2);
ENABLE_HIGH;
}
void check_busy(void)
{
P1DIR &= ~(BIT3); // make P1.3 as input
while((P1IN&BIT3)==1)
{
data_read();
}
P1DIR |= BIT3; // make P1.3 as output
}
void send_command(unsigned char cmd)
{
check_busy();
WRITE;
CWR;
P1OUT = (P1OUT & 0xF0)|((cmd>>4) & 0x0F); // send higher nibble
data_write(); // give enable trigger
P1OUT = (P1OUT & 0xF0)|(cmd & 0x0F); // send lower nibble
data_write(); // give enable trigger
}
void send_data(unsigned char data)
{
check_busy();
WRITE;
DR;
P1OUT = (P1OUT & 0xF0)|((data>>4) & 0x0F); // send higher nibble
data_write(); // give enable trigger
P1OUT = (P1OUT & 0xF0)|(data & 0x0F); // send lower nibble
data_write(); // give enable trigger
}
void send_string(char s)
{
while(s)
{
send_data(*s);
s++;
}
}
void lcd_init(void)
{
P1DIR |= 0xFF;
P1OUT &= 0x00;
send_command(0x33);
send_command(0x32);
send_command(0x28); // 4 bit mode
send_command(0x0E); // clear the screen
send_command(0x01); // display on cursor on
send_command(0x06); // increment cursor
send_command(0x80); // row 1 column 1
}
#include “lcd.h”
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
lcd_init();
send_string(“Hello”);
send_command(0xC0);
send_string(“World”);
while(1){}
}
I am using MPlab to read data from a pic micro controller. I am using pic18F87J11.
The data that I want to read is on pin 3 of the DB9 of the RS232, and my RS232 is connected to the pic micro controller.
Can anyone help me or give me a simple sample code to do that??
Thank you,
//
// Designed by www.MCUExamples.com
// rasika0612#gmail.com
// Serial communications example. Echo data comes to serial port
// using serial receive interrupt.
//
#include <p18f4520.h>
#pragma config OSC = HS // 20MHz Crystal, (HS oscillator)
#pragma config PBADEN = OFF // PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config WDT = OFF // watch dog timer off
#pragma config LVP = OFF // Low voltage program off
unsigned char cUART_char;
unsigned char cUART_data_flg;
void init_uart(void);
void UART_putc(unsigned char c);
void InterruptHandlerLow ();
void main()
{
init_uart(); // init UART module
while (1) // infinite loop which handles ncoming data as they arrive
{
if (cUART_data_flg==1)// if new data available, send it back through USART tx line (echo it)
{
UART_putc(cUART_char);
cUART_data_flg=0; // clear new data flag so one charactor will echoed once
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow (void)
{
_asm
goto InterruptHandlerLow //jump to interrupt routine
_endasm
}
//----------------------------------------------------------------------------
// Low priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerLow
void InterruptHandlerLow ()
{
if (PIR1bits.RCIF==1)//is interrupt occured by EUSART receive?,
//then RCREG is full we have new data (cleared when RCREG is read)
{
if(RCSTA&0x06) //more efficient way than following commented method to check for reception error
//if(RCSTAbits.FERR==1 || RCSTAbits.OERR==1 )
{
RCSTAbits.CREN=0; //Overrun error (can be cleared by clearing bit CREN)
cUART_char=RCREG; //clear Framing error
RCSTAbits.CREN=1;
}
else
{
cUART_char = RCREG; // read new data into variable
cUART_data_flg = 1; // new data received. so enable flg
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void init_uart(void) // init UART module for 9600bps boud, start bit 1, stopbit 1, parity NONE
{
cUART_data_flg=0; // init data receive flag to zero (no data)
TRISCbits.TRISC7=1; //Make UART RX pin input
TRISCbits.TRISC6=0; //Make UART TX pin output
SPBRGH = 0x02; //9600bps 20MHz Osc
SPBRG = 0x08;
RCSTAbits.CREN=1; //1 = Enables receiver
RCSTAbits.SPEN=1; //1 = Serial port enabled (configures RX/DT and TX/CK pins as serial port pins)
BAUDCONbits.BRG16=1;//1 = 16-bit Baud Rate Generator – SPBRGH and SPBRG
TXSTAbits.SYNC=0; //0 = Asynchronous mode
TXSTAbits.BRGH=1; //1 = High speed
TXSTAbits.TXEN=1; //1 = Transmit enabled
RCONbits.IPEN = 1; //enable Interrupt priority levels
IPR1bits.RCIP=0; // EUSART Receive Interrupt Priority 0 = Low priority
PIE1bits.RCIE=1; // 1 = Enables the EUSART receive interrupt
INTCONbits.GIEL = 1;//enable interrupts
INTCONbits.GIEH = 1;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void UART_putc(unsigned char c)
{
TXSTAbits.TXEN=0;// disable transmission
TXREG=c; // load txreg with data
TXSTAbits.TXEN=1; // enable transmission
while(TXSTAbits.TRMT==0) // wait here till transmit complete
{
Nop();
}
}
I'm trying to get the Timer1 on my PIC18F2550 to fire interrupts every second for countdowns. So far I've been able to establish interrupt priority correctly, as well as other settings, however my ISR only fires once. I've set up my program to print the amount of seconds left in the countdown onto the LCD, so it's obvious to the user how many interrupts have passed. I've made sure to clear the proper interrupt flags in the ISR, since that's what was the source of the problem for the majority of the people having the same issue on google, but this didn't fix it. Everything else about my program has worked fine so far.
(For the sake of testing whether or not the right priority has fired, low counts up instead of down)
Here's the code snippet
//First testing program for PIC18F2550
#include <p18f2550.h>
#include <stdlib.h>
#include <delays.h>
#define _XTAL_FREQ 4915200
#pragma config PLLDIV = 1
#pragma config CPUDIV = OSC1_PLL2
#pragma config FOSC = XT_XT
#pragma config MCLRE = ON
#pragma config BOR = OFF
#pragma config WDT = OFF
#pragma config IESO = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
unsigned char Countdown = 30; (other vars, fcns omitted)
#pragma code high_vector = 0x08
void highvectinterrupt(void){
_asm goto highisr _endasm
}
#pragma code low_vector = 0x18
void lowvectinterrupt(void){
_asm goto lowisr _endasm
}
(...)
void highisr(void){
Countdown--;
PIR1bits.TMR1IF = 0;
}
void lowisr(void){
Countdown++;
PIR1bits.TMR1IF = 0;
}
void main(void){
UCONbits.USBEN=0; //Setup I/O
UCFGbits.UTRDIS=1;
OSCCONbits.SCS1 = 0;
OSCCONbits.SCS0 = 0;
BAUDCONbits.TXCKP=0;
SPBRG = 0x3F; //1200 baud
TRISA = 0x00;
TRISB = 0xFF;
TRISC = 0x00;
beephigh(); //Done, clear the line and beep speaker 1
LATA = 0; //reset
LATC = 0;
Delay10KTCYx(8);
LATAbits.LATA2 = 1; //load the reset
Delay10KTCYx(8);
LATAbits.LATA3 = 1; //stop reset
LATAbits.LATA4 = 1;
LATAbits.LATA2 = 0;
Delay10KTCYx(123);
initlcd();
Delay10KTCYx(10);
setupUI();
LATAbits.LATA0 = 0; //Done, clear the line and beep speaker 2
beeplow();
INTCON = 0; //Reset high interrupt flags and disable interrupts
T1CON = 0x11110100; //16 bit r/w; internal system clock; 8x prescale; timer1 osc disabled
TMR1H = 0; //Clear the counting register
TMR1L = 0;
PIE1bits.TMR1IE = 1; //Enable Interrupts on Timer1
PIR1bits.TMR1IF = 0; //Clear the flag if set
RCONbits.IPEN = 1; //Enable priority levels
INTCON2bits.TMR0IP = 0; //Timer0 on low priority
IPR1bits.TMR1IP = 0; //Timer1 on low priority
IPR1bits.RCIP = 1; //RS232 on high priority
INTCONbits.GIEL = 1; //Enable all low priority interrupts
INTCONbits.GIEH = 1; //Enable all high priority (must be enabled for low priority)
T1CONbits.TMR1ON = 1; //Turn Timer1 on
while(1){ //Idle and refresh screen
Delay10KTCYx(8);
bin2ascii(Countdown);
cmdlcd(0xCE);
putclcd(ConvRegTens);
putclcd(ConvRegOnes);
}
}
Ultimately I'm staring at an LCD with "31" on it. It's likely a single flag that I'm not setting properly that's causing nothing to work right, but as far as I've checked everything's being enabled and being cleared properly. What am I doing wrong? I'd appreciate any help, this is enormously frustrating.
Also: I've cleared all breakpoints so it's not halting anywhere, and program the latest version on compile. So I've ruled out running an old busted version of the code.
Edit: To clarify, this code is only for functionality; it will not fire every second but rather much faster. Once I get it working I'll play the overflow counting to get it to 1 second.
You are not finishing ISR routine correctly!
#pragma code low_vector = 0x18
void lowvectinterrupt(void){
_asm goto lowisr _endasm
}
After ISR execution the interrupt must be switched on again, so the lowvectinterrupt must be finished with RETFIE instruction and at least flags and WREG register must be restored.
Normaly is in ISR routine declared like:
static void interrupt isr(void)
{
}
I'm using the PIC18F4550 from microchip with the c compiler: by default the 'program memory' is used, but now I want to use the 'data memory' because it gives me a big more functionality, can enyone just tell me how can I to that in the program language C.
That the code:
#pragma code
/******************************************************************************/
void main (void)
{
TRISD = 0x00; // PORTD als uitgang
TRISB = 0b00110000; // RB4 en RB5 als ingang
TRISA = 0x00; // RA output
RCONbits.IPEN = 0; // prioriteit uit
INTCONbits.GIE = 1; // enable interrupt
INTCONbits.RBIE = 1; // interrupt portB aan
while(1)
{
_asm sleep _endasm
}
}
#pragma interrupt ISR
void ISR (void)
{
int rood[] = {0,0,1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,1,1,0,1,0,1,0,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,1,1,1,1,0,1,1,};
if (INTCONbits.RBIF==1)
{
if(PORTBbits.RB5==0) // S3 ingedrukt ?
{
int i = 0;
int b;
do {
LATAbits.LATA2 = rood[i];
LATDbits.LATD1 ^= 1;
b = 0;
do {
b++;
}while(b <= 1500);
i++;
}while(rood[i] <= 50);
//LATDbits.LATD1 ^= 1; // D2 togglen
}
}
INTCONbits.RBIF = 0;
}
The data sheets for this device seem to indicate that the Data Memory is static ram, and that there is no data path from there to the instruciton decode logic, ie, the data memory cannot be used to store program code for execution. If that was your goal, you are out of luck.
In terms of allocating volatile storage, since the program memory does not appear to include any RAM, my guess is that the C compiler will automatically allocate all variables, etc from the data ram.
That leaves only the choice between the "data" EEPROM and the "program" flash for storage of non-volatile (or semi-volatile) data. There you may have to dig into the documentation - it could be this is done with compiler pragmas, or a linker map file, or it could be that access has to be handled indirectly and explicitly through registers.