Good night! To everyone seeing this, Im an student and I have a problem here, hope someone can help me out. Thanks
So Im using a micro PIC16F877A to make a digital counter that shows on a display, so my goal in this code is to make this counter count to 36 and then restart from 0. So I did an If statement at the bottom where if tens(de) reach 3 and units(un) reach 6, it starts from 0 again.
More data: Currently working on MPLAB-X and Proteus, using C language, the Bit config of the pic will be attach here and the proteus proyect as well.
I suppose there is better ways to make this on a PIC, but all this is really new to me, so I'll be glad to learn about it.
Here is the code:
#include <xc.h>
#define _XTAL_FREQ 4000000
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#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 (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
int ar = 0;
int de = 0, un = 0, A = 0;
int Display[10] = {0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8, 0X80, 0X98};
void visualizacion(void);
void incremento(void);
void main(void)
{
TRISC = 0X00; // PUERTO C COMO SALIDA
TRISB = 0X00; // PUERTO B SALIDA
TRISDbits.TRISD0 = 1; // PUERTO D0 COMO ENTRADA
while (1)
{
if (PORTDbits.RD0 == 1)
{
ar = 1;
}
if (PORTDbits.RD0 == 0 && ar == 1)
{
un = un+1;
ar = 0;
}
visualizacion();
incremento();
}
}
void visualizacion(void)
{
PORTC = 0X01;
PORTB = Display[un];
__delay_us (500);
PORTC = 0X02;
PORTB = Display[de];
__delay_us (500);
}
void incremento(void)
{
if (un >= 10)
{
un = 0;
de = de+1;
}
if(de >= 3 && un >= 6)
{
de = 0;
}
}
This is the bit config
And this is the error:
output error image
Thanks!
The question is answered in the comments to the question (by mlwn & stark):
replace if(de>=3) && (un>=6){ with : if (de >= 3 && un >= 6) {
Also change de=0; to de=0; un=0; otherwise you rest to 6.
Related
I'm using PIC18F46K22 to display the time from DS3231 rtc device via I2C. I'm facing issue while setting the acknowledgement (ACKEN). I'm feeling something wrong in my configuration especially in Pin Configuration and setting the baud rate with SSP1ADD.
I'm using 20MHz and my DS3231 is supports for 400kHz.
While setting the acknowledgement(ACKEN), program getting hang, I mean, it is not able to set it not coming out from the step.
Please help me to fix the issue, please find the attached code.
//PCI18F46K22 Pin Configurations:
#define _XTAL_FREQ 20000000
// CONFIG1H
#pragma config FOSC = HSHP // Oscillator Selection bits->HS oscillator (high power > 16 MHz)
// PLLCFG changed
#pragma config PLLCFG = OFF // 4X PLL Enable->Oscillator used directly
// PRICLKEN changed
#pragma config PRICLKEN = OFF // Primary clock enable bit->Primary clock is always enabled
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit->Oscillator Switchover mode disabled
// CONFIG2L
// - PWRTEN
#pragma config PWRTEN = ON // Power-up Timer Enable bit->Power up timer disabled
// - BOREN = SBORDIS
#pragma config BOREN = ON // Brown-out Reset Enable bits->Brown-out Reset enabled in hardware only (SBOREN is disabled)
#pragma config BORV = 190 // Brown Out Reset Voltage bits->VBOR set to 1.90 V nominal
// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer Enable bits->Watch dog timer is always disabled. SWDTEN has no effect.
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits->1:32768
// CONFIG3H
#pragma config CCP2MX = PORTC1 // CCP2 MUX bit->CCP2 input/output is multiplexed with RC1
#pragma config PBADEN = OFF // PORTB A/D Enable bit->PORTB<5:0> pins are configured as digital I/O on Reset
#pragma config CCP3MX = PORTB5 // P3A/CCP3 Mux bit->P3A/CCP3 input/output is multiplexed with RB5
#pragma config HFOFST = ON // HFINTOSC Fast Start-up->HFINTOSC output and ready status are not delayed by the oscillator stable status
#pragma config T3CMX = PORTC0 // Timer3 Clock input mux bit->T3CKI is on RC0
#pragma config P2BMX = PORTC0 // ECCP2 B output mux bit->P2B is on RC0
#pragma config MCLRE = EXTMCLR // MCLR Pin Enable bit->MCLR pin enabled, RE3 input pin disabled
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset
#pragma config LVP = ON // Single-Supply ICSP Enable bit->Single-Supply ICSP enabled if MCLRE is also 1
#pragma config XINST = OFF // Extended Instruction Set Enable bit->Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG = OFF // Background Debug->Disabled
// CONFIG5L
#pragma config CP0 = OFF // Code Protection Block 0->Block 0 (000800-003FFFh) not code-protected
#pragma config CP1 = OFF // Code Protection Block 1->Block 1 (004000-007FFFh) not code-protected
#pragma config CP2 = OFF // Code Protection Block 2->Block 2 (008000-00BFFFh) not code-protected
#pragma config CP3 = OFF // Code Protection Block 3->Block 3 (00C000-00FFFFh) not code-protected
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit->Boot block (000000-0007FFh) not code-protected
#pragma config CPD = OFF // Data EEPROM Code Protection bit->Data EEPROM not code-protected
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection Block 0->Block 0 (000800-003FFFh) not write-protected
#pragma config WRT1 = OFF // Write Protection Block 1->Block 1 (004000-007FFFh) not write-protected
#pragma config WRT2 = OFF // Write Protection Block 2->Block 2 (008000-00BFFFh) not write-protected
#pragma config WRT3 = OFF // Write Protection Block 3->Block 3 (00C000-00FFFFh) not write-protected
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit->Configuration registers (300000-3000FFh) not write-protected
#pragma config WRTB = OFF // Boot Block Write Protection bit->Boot Block (000000-0007FFh) not write-protected
#pragma config WRTD = OFF // Data EEPROM Write Protection bit->Data EEPROM not write-protected
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection Block 0->Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
#pragma config EBTR1 = OFF // Table Read Protection Block 1->Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
#pragma config EBTR2 = OFF // Table Read Protection Block 2->Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
#pragma config EBTR3 = OFF // Table Read Protection Block 3->Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit->Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
//-----------------------------
//--I2C Configurations
void I2C_Initialize(const unsigned long feq_K) //Begin IIC as master
{
TRISC3 = 1; //Set SCL pint as input pin
TRISC4 = 1; //Set SDA pin as input pin
ANSELCbits.ANSC3=0; //Disable Analog pin
ANSELCbits.ANSC4=0; //Disable Analog pin
SSP1CON1=0b00101000;; /* 0x00101000 - Enable SSP port for I2C Master mode, clock = FOSC / (4 * (SSPADD+1))*/
SSP1CON2=0b00000000;
SSP1CON3=0b00000000;
SSP1STAT=0b00000000;
SSP1ADD=(_XTAL_FREQ/(4*feq_K*100))-1;
}
void I2C_Hold()
{
while ( (SSP1CON2 & 0b00011111) || (SSP1STAT & 0b00000100) ) ; //check the bis on registers to make sure the IIC is not in progress
}
void I2C_Begin()
{
I2C_Hold(); //Hold the program is I2C is busy
SSP1CON2bits.SEN = 1;
}
void I2C_End()
{
I2C_Hold(); //Hold the program is I2C is busy
SSP1CON2bits.PEN = 1;
}
void I2C_Write(unsigned data)
{
I2C_Hold(); //Hold the program is I2C is busy
SSP1BUF = data;
}
unsigned short I2C_Read(unsigned short ack)
{
unsigned short incoming;
I2C_Hold();
SSP1CON2bits.RCEN = 1;
I2C_Hold();
incoming = SSP1BUF; //get the data saved in SSP1BUF
I2C_Hold();
SSP1CON2bits.ACKDT = (ack)?0:1; //check if ack bit received
SSP1CON2bits.ACKEN = 1;
return incoming;
}
//-------------------------------
//--DS3231 Functions to set/get timings
#include "i2c.h"
typedef struct
{
uint8_t sec;
uint8_t min;
uint8_t hour;
uint8_t weekDay;
uint8_t date;
uint8_t month;
uint8_t year;
}rtc_t;
void rtc_set_clock(rtc_t *rtc);
void get_date_time(rtc_t *rtc);
char* rtc_get_month(rtc_t *rtc);
/****** Functions for RTC module *******/
int BCD_2_DEC(int to_convert)
{
return (to_convert >> 4) * 10 + (to_convert & 0x0F);
}
int DEC_2_BCD (int to_convert)
{
return ((to_convert / 10) << 4) + (to_convert % 10);
}
void rtc_set_clock(rtc_t *rtc)
{
I2C_Begin();
I2C_Write(0xD0); //0x1101 0000
I2C_Write(0);
I2C_Write(DEC_2_BCD(rtc->sec)); //update sec
I2C_Write(DEC_2_BCD(rtc->min)); //update min
I2C_Write(DEC_2_BCD(rtc->hour)); //update hour
I2C_Write(1); //ignore updating day
I2C_Write(DEC_2_BCD(rtc->date)); //update date
I2C_Write(DEC_2_BCD(rtc->month)); //update month
I2C_Write(DEC_2_BCD(rtc->year)); //update year
I2C_End();
}
void get_date_time(rtc_t *rtc)
{
//START to Read
I2C_Begin();
I2C_Write(0xD0);
I2C_Write(0);
I2C_End();
//READ
I2C_Begin();
I2C_Write(0xD1); // Initialize data read
rtc->sec = BCD_2_DEC(I2C_Read(1));
rtc->min = BCD_2_DEC(I2C_Read(1)); // Read sec from register
rtc->hour = BCD_2_DEC(I2C_Read(1));
I2C_Read(1);
rtc->date = BCD_2_DEC(I2C_Read(1));
rtc->month = BCD_2_DEC(I2C_Read(1));
rtc->year = BCD_2_DEC(I2C_Read(1));
I2C_End();
//END Reading
I2C_Begin();
I2C_Write(0xD1); // Initialize data read
I2C_Read(1);
I2C_End();
return;
}
char* rtc_get_month(rtc_t *rtc) {
switch(rtc->month){
case 1: return "JAN";
case 2: return "FEB";
case 3: return "MAR";
case 4: return "APR";
case 5: return "MAY";
case 6: return "JUN";
case 7: return "JUL";
case 8: return "AUG";
case 9: return "SEP";
case 10: return "OCT";
case 11: return "NOV";
case 12: return "DEC";
}
return 0;
}
//------------------------
//My main function for PIC18F46K22 for DS3231 using I2C (SSP1)
rtc_t rtc;
void main()
{
char msg_welcome[15] = "LCD Read.";
char retValue[17];
char a,b;
short int i;
TRISC2 = 0;
LATC2 = 0;
PORTCbits.RC2 = 0;
I2C_Initialize(100);
Lcd_Init();
__delay_ms(5);
rtc.hour = 23; // 23:59:10 am
rtc.min = 59;
rtc.sec = 10;
rtc.date = 21; //21th Jan 2019
rtc.month = 1;
rtc.year = 19;
rtc_set_clock(&rtc);
Lcd_Clear();
Lcd_Write_String(1,1,"Start communic:");
Lcd_Write_String(2,1,"Timers:");
__delay_ms(1000);
LATC2 = 1;
Lcd_Clear();
while(1){
get_date_time(&rtc);
for(i=0; i< 17; i++)
retValue[i] = '\0';
sprintf(retValue, "Bytes: %02d-%s-%02d", rtc.date, rtc_get_month(&rtc), rtc.year);
Lcd_Write_String(1,1,retValue);
for(i=0; i< 17; i++)
retValue[i] = '\0';
sprintf(retValue," %02d:%02d:%02d", rtc.hour, rtc.min, rtc.sec);
Lcd_Write_String(2,1,retValue);
__delay_ms(1000);
}
return;
}
I am trying to setup basic serial communication between dsPIC33FJ64GP802 and a terminal and PC using UART module. However, UART does not transmit more than once character. I am using MPLAB-X (V 5.05). I also use snap debugger to program the dsPic. I am trying to figure the error in my code. I tried changing the dsPic itself and the Bluetooth module as well. It did not work. I don't know if I am missing some bits.
// FBS
#pragma config BWRP = WRPROTECT_OFF // Boot Segment Write Protect (Boot Segment may be written)
#pragma config BSS = NO_FLASH // Boot Segment Program Flash Code Protection (No Boot program Flash segment)
#pragma config RBS = NO_RAM // Boot Segment RAM Protection (No Boot RAM)
// FSS
#pragma config SWRP = WRPROTECT_OFF // Secure Segment Program Write Protect (Secure segment may be written)
#pragma config SSS = NO_FLASH // Secure Segment Program Flash Code Protection (No Secure Segment)
#pragma config RSS = NO_RAM // Secure Segment Data RAM Protection (No Secure RAM)
// FGS
#pragma config GWRP = OFF // General Code Segment Write Protect (User program memory is not write-protected)
#pragma config GSS = OFF // General Segment Code Protection (User program memory is not code-protected)
// FOSCSEL
#pragma config FNOSC = LPRCDIVN // Oscillator Mode (Internal Fast RC (FRC) with divide by N)
#pragma config IESO = ON // Internal External Switch Over Mode (Start-up device with FRC, then automatically switch to user-selected oscillator source when ready)
// FOSC
#pragma config POSCMD = NONE // Primary Oscillator Source (Primary Oscillator Disabled)
#pragma config OSCIOFNC = OFF // OSC2 Pin Function (OSC2 pin has clock out function)
#pragma config IOL1WAY = ON // Peripheral Pin Select Configuration (Allow Only One Re-configuration)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Both Clock Switching and Fail-Safe Clock Monitor are disabled)
// FWDT
#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler (1:32,768)
#pragma config WDTPRE = PR128 // WDT Prescaler (1:128)
#pragma config WINDIS = OFF // Watchdog Timer Window (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = ON // Watchdog Timer Enable (Watchdog timer always enabled)
// FPOR
#pragma config FPWRT = PWR128 // POR Timer Value (128ms)
#pragma config ALTI2C = OFF // Alternate I2C pins (I2C mapped to SDA1/SCL1 pins)
// FICD
#pragma config ICS = PGD1 // Comm Channel Select (Communicate on PGC1/EMUC1 and PGD1/EMUD1)
#pragma config JTAGEN = OFF // JTAG Port Enable (JTAG is Disabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#include <stdbool.h>
#include "stdio.h"
#include <string.h>
//delay in milliseconds
void delay_milliseconds(long double milliSecond)
{
milliSecond = (milliSecond * 147);
long double i;
for(i = 0; i<milliSecond;i++);
}
/*
Main application
*/
void UART1_setup(void)
{
U1BRG = 25;
U1MODE = 0;
U1MODEbits.UEN = 0;
U1MODEbits.UARTEN = 1; //enable the module
U1STAbits.UTXEN = 1; //enable transmissiond
U1MODEbits.BRGH = 0;
U1STAbits.UTXISEL1 = 1;
U1STAbits.UTXISEL0 = 0;
U1STAbits.UTXBF = 0;
U1STAbits.URXDA = 1;
U1STAbits.OERR = 0;
U1STAbits.FERR = 0;
U1STAbits.PERR = 0;
INTCON1bits.NSTDIS = 0;
IFS0bits.U1RXIF = 0;
IEC0bits.U1RXIE = 1;
IPC2bits.U1RXIP = 7;
}
char UART1_Read(void)
{
while(!(U1STAbits.URXDA == 1))
{
}
if ((U1STAbits.OERR == 1))
{
U1STAbits.OERR = 0;
}
return U1RXREG;
}
void UART1_Write(char txData)
{
while(U1STAbits.UTXBF == 1)
{
}
U1TXREG = txData; // Write the data byte to the USART.
}
void printString(char *data)
{
int len = strlen(data);
int i =0;
for( i = 0; i<len; i++)
{
char txData = *(data + i);
UART1_Write(txData);
}
}
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
//Clear receive interrupt flag
IFS0bits.U1RXIF = 0;
}
uint8_t data[2];
void pinSetup(void)
{
//set directions
TRISBbits.TRISB11 = 0; //TX
TRISBbits.TRISB10 = 1; //Rx
//***************************************************************************&&
__builtin_write_OSCCONL(OSCCON & 0xbf); // unlock PPS
RPINR18bits.U1RXR = 0x000B; //RB11->UART1:U1RX
RPOR5bits.RP10R = 0x0003; //RB10->UART1:U1TX
//RPINR0bits.INT1R = 0x0005; //RB5->EXT_INT:INT1
__builtin_write_OSCCONL(OSCCON | 0x40); // lock PPS
//////////////////**********************************************************************&&&&&&&&
}
int main(void)
{
pinSetup();
I2C1_init();
UART1_setup();
while(true)
{
UART1_Write('A');
}
}
Sometimes on initial startup, the UART RX line transits spontaneously causing the Receive buffer to overflow and its associated bit to be set. This disables the UART module until the overrun bit is cleared. Try clearing the receive buffer overflow bit each time you want to send a character and see if it helps
The strlen () function returns the number of characters in the string up to the null terminator. But when you write 'A' you have just a single character and not a complete string with a terminator. So try "ABC" e.g.
I don't understand the use of 0xFF in an array of pointers. I want to control a keypad. My code is:
// CONFIGURATION BITS
#pragma config FOSC = HS // Oscillator Selection bits (XT oscillator)
#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
// DEFINING LCD PINS
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
// DEFINING KEYPAD PINS
#define KP_R1 PORTBbits.RB1
#define KP_R2 PORTBbits.RB2
#define KP_R3 PORTCbits.RC1
#define KP_R4 PORTCbits.RC2
#define KP_C1 PORTBbits.RB3
#define KP_C2 PORTBbits.RB4
#define KP_C3 PORTBbits.RB6
#define KP_C4 PORTBbits.RB7
#include <xc.h>
#include "lcd.h"
#include <stdio.h>
#include <stdlib.h>
const char *keyPadMatrix[] =
{
"1","2","3","A",
"4","5","6","B",
"7","8","9","C",
"*","0","#","D",
0xFF
};
void kbd_init();
void kbd_init(){
// SETTING THE DATA DIRECTION REGISTERS
PORTB = 0x00;
TRISB = 0xD9; // RB7-1 RB6-1 RB5-0 RB4-1 RB3-1 RB2-0 RB1-0 RB0-1 ( 1=Input, 0=Output)
PORTC = 0x00;
TRISC = 0x90; // RC7-1 RC6-0 RC5-0 RC4-1 RC3-0 RC2-0 RC1-0 RC0-0 ( 1=Input, 0=Output)
OPTION_REGbits.nRBPU = 1;
}
char old_key;
char *kbd_getc();
char *kbd_getc(){
char row;
char key = 0;
for( row = 0b00000001; row < 0b00010000; row <<= 1 )
{
{ // turn on row output
KP_R1 = (row & 0x0001)>>0;
KP_R2 = (row & 0x0002)>>1;
KP_R3 = (row & 0x0004)>>2;
KP_R4 = (row & 0x0008)>>3;
__delay_ms(1);
}
// read colums - break when key press detected
if( KP_C1 == 1 ){
break;
}
key++;
if( KP_C2 == 1 ){
break;
}
key++;
if( KP_C3 == 1 ){
break;
}
key++;
if( KP_C4 == 1 ){
break;
}
key++;
}
KP_R1 = 0;
KP_R2 = 0;
KP_R3 = 0;
KP_R4 = 0;
if (key!=old_key){
old_key=key;
return keyPadMatrix[key];
}
else{
return keyPadMatrix[0x10];
}
}
void main()
{
TRISD = 0x00; //PORTD as output for LCD
Lcd_Init();
Lcd_Clear();
while(1)
{
Lcd_Set_Cursor(1,1);
char *keypress;
keypress = kbd_getc();
Lcd_Write_String(keypress);
__delay_ms(50);
}
}
The idea is that when you press a key, an LCD show that key, and when you don't press anything, the LCD doesn't show anything. If you change 0xFF for something like "w" the keypad does the trick, but instead of showing anything, it shows "w" (as expected). But when you use 0xFF the keypad doesn't work. I don't understand the use of 0xFF in the array of pointers. I copied the code from a website, but I making some changes because the original doesn't work either.
Note:
void Lcd_Write_String(char *a)
{
int i;
for(i=0;a[i]!='\0';i++)
Lcd_Write_Char(a[i]);
}
I am new to writing firmware for 8-bit PICs and could use some help with my code. I am using a PIC16F1829 for an LED module which gets RX commands. I am just trying to get the basics setup like turn on LEDs when a certain value is received on RX pin, but can't even get that.
Would like to get UART working via interrupts but can't even get it working with polling in main loop. My interrupt vector is commented out in the code below.
RX pin: RC5
TX pin: RB7
Pin to toggle LEDs on and off: RA5
Pin RA5 works fine to toggle LEDs on and off. TX pin is working, though I have not confirmed if interrupt TXIF is also not working like RCIF is not working.
I have tried reading RCIF and PIR1bits.RCIF. Both of them compiled. Neither one worked. I have tried this on two different PICs on 2 different LED modules. They turn on, but reading RX pin didn't work on either.
Variable RXIN is initially defined as 3 and thus due to the RXIN-- loop within the main loop the lights flash 3 times at startup so I know it is entering the main loop. But as far as I can tell the RCIF interrupt is not firing upon reception at RX pin.
I have confirmed on oscilloscope that the signal into RX and out of TX pins using same baud, so I think baud rate is configured correctly (300 baud, 8N1.) I have also confirmed on oscilloscope RX pin receiving strong and clean 5V signal. Neither polling RCIF or using an interrupt service routing has worked thus far. If anyone can see the issues with my code that I am not seeing, your help would be greatly appreciated.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
// This is for 300 baud rate
#define _BAUD_PRESCALER_LOW_ 0x2A
#define _BAUD_PRESCALER_HIGH_ 0x68
#define _XTAL_FREQ 32000000
#pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF // Watchdog Timer Enable->WDT enabled
#pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = OFF // Internal/External Switchover->Internal/External Switchover mode is disabled
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is disabled
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = ON // PLL Enable->4x PLL enabled
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF
int flagRXFramingError = 0;
int flagRXOverrunError = 0;
volatile unsigned char RXIN = 3;
unsigned char UARTRead(){
return RCREG;
}
void writeRXIN(unsigned char a){
RXIN = a;
}
void TX(unsigned char a){
while(!TXIF){}
TXREG = a;
}
int main(int argc, char** argv) {
// SCS FOSC; SPLLEN disabled; IRCF 8MHz_HF;
OSCCON = 0xF0;
// TUN 0;
OSCTUNE = 0x00;
// Set the secondary oscillator
// Wait for PLL to stabilize
while(PLLR == 0)
{
}
// WDTPS 1:65536; SWDTEN OFF;
WDTCON = 0x16;
__delay_ms(5);
GIE = 1; // Global interrupts enabled
__delay_ms(5);
PEIE = 1; // Active peripheral interrupts enabled
__delay_ms(5);
RCIE = 1; // Enable USART Receive interrupt
__delay_ms(5);
TXIE = 1; // Enable USART Transmitter interrupt
__delay_ms(5);
ADIE = 1; // Enable ADC interrupts
__delay_ms(5);
RXDTSEL = 0; // RX is on RC5 pin
__delay_ms(5);
TXCKSEL = 0; // TX is on RB7 pin
__delay_ms(5);
TRISC5 = 1; // RX pin set as input
__delay_ms(5);
SPEN = 1; // Serial Port Enabled
__delay_ms(5);
SYNC = 0; // Asynchronous mode
__delay_ms(5);
RX9 = 0; // 8 bit reception
__delay_ms(5);
TX9 = 0; // 8-bit transmission
__delay_ms(5);
CREN = 1; // Receiver enabled
__delay_ms(5);
TXEN = 1; // Transmitter enabled
__delay_ms(5);
BRG16 = 1; // 16-bit baud generation
__delay_ms(5);
BRGH = 1; // High baud rate enabled
__delay_ms(5);
ABDEN = 0; // Auto baud detect disabled
__delay_ms(5);
// Baud prescaler n = [Fosc/(D*BR)] - 1
SPBRGH = _BAUD_PRESCALER_HIGH_;
__delay_ms(5);
SPBRGL = _BAUD_PRESCALER_LOW_;
__delay_ms(5);
TRISC6 = 0; // IadjPWM pin configured as output
__delay_ms(5);
ANSC6 = 0; // IadjPWM pin not analog input
__delay_ms(5);
TRISA5 = 0; // DimPWM pin configured as output
__delay_ms(5);
LATC6 = 1; // Max current for now until PWM written
__delay_ms(5);
while(1){
// Inline assembly code to clear watchdog timer
//asm("CLRWDT");
/*if(RXIN == 5){
RA5 = 1;
}
else{
RA5 = 0;
}*/
if(PIR1bits.RCIF){
writeRXIN(UARTRead());
//RA5 = 0;
TX(RXIN);
} // end if RCIF
while(RXIN > 0){
RA5 = 1;
__delay_ms(100);
RA5 = 0;
__delay_ms(100);
RXIN--;
}
}
// infinite loop
// never leave this loop
RA5 = 1;
return (EXIT_SUCCESS);
} // end main
/*void interrupt ISR(void){
if(RCIF){// if USART Receive interrupt flag
RA5 = 1;
if(FERR){
flagRXFramingError = 1;
SPEN = 0;
SPEN = 1;
}
if(OERR){
flagRXOverrunError = 1;
CREN = 0;
CREN = 1;
}
while(RCIF){ // RCIF high as long as there is data in FIFO register. Read RCREG to clear RCIF flag
writeRXIN(UARTRead());
}
RA5 = 0;
}
if (TXIF){// if USART Transmit interrupt
TXIF = 0; // Clear interrupt flag
}
} // end ISRs*/
Some microcontrollers stop receiving bytes if there was some kind of error. Be sure to clear those errors. Usually by clearing some UART control register bits.
SOLVED THE PROBLEM
I am not sure what exactly solved the problem but I will share the major changes I made and the new code.
I had TXIE enabled. TXIF is almost always high, so it generates
continuous interrupts. I don't see a reason to enable TX interrupts,
though there may be a good one. If you want to TX wait until TXIF is
not zero and transmit, otherwise why use the flag?
I had the interrupts enabling in the wrong order. I should have
enabled the peripherals, then their individual interrupts if
necessary, then PEIE, and finally GIE.
I wasn't handling FERR and OERR in my interrupt, though they may
be firing and causing interrupts.
Also I had RXDTSEL set wrong in my original code. Here is the new, working code. Right now all it does is echo the RX signal and blink the LEDs the number of times that is transmitted.
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
// This is for 300 baud rate
#define _BAUD_PRESCALER_LOW_ 0x2A
#define _BAUD_PRESCALER_HIGH_ 0x68
#define _XTAL_FREQ 32000000
#define _PIN_DIMPWMPIN_ RA5
#pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF // Watchdog Timer Enable->WDT enabled
#pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = OFF // Internal/External Switchover->Internal/External Switchover mode is disabled
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is disabled
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = ON // PLL Enable->4x PLL enabled
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF
int flagRXFramingError = 0;
int flagRXOverrunError = 0;
volatile unsigned char RXIN = 3;
unsigned char RX(){
return RCREG;
}
void writeRXIN(volatile unsigned char a){
RXIN = a;
}
void TX(unsigned char a){
while(!PIR1bits.TXIF); // TXIF is usually 1, only 0 when busy transmitting
TXREG = a;
}
int main(int argc, char** argv) {
// SCS FOSC; SPLLEN disabled; IRCF 8MHz_HF;
OSCCON = 0xF0;
// TUN 0;
OSCTUNE = 0x00;
// Set the secondary oscillator
// Wait for PLL to stabilize
while(OSCSTATbits.PLLR == 0){}
ADCON0bits.ADON = 0;
ANSELA = 0x00;
ANSELB = 0x00;
ANSELC = 0x00;
PIE1bits.ADIE = 0; // Disable ADC interrupts
TRISCbits.TRISC5 = 1; // RX pin set to input
TRISCbits.TRISC6 = 0; // IadjPWM pin configured as output
TRISAbits.TRISA5 = 0; // DimPWM pin configured as output
LATCbits.LATC6 = 1; // Max current for now until PWM written
//UART Init
BAUDCONbits.BRG16 = 1; // 16-bit baud generation
TXSTAbits.BRGH = 1; // High baud rate enabled
BAUDCONbits.ABDEN = 0; // Auto baud detect disabled
// Baud prescaler n = [Fosc/(D*BR)] - 1
SPBRGH = _BAUD_PRESCALER_HIGH_;
__delay_ms(1);
SPBRGL = _BAUD_PRESCALER_LOW_;
__delay_ms(1);
APFCON0bits.RXDTSEL = 1; // RX is on RC5 pin
APFCON0bits.TXCKSEL = 0; // TX is on RB7 pin
TXSTAbits.SYNC = 0; // Asynchronous mode
RCSTAbits.SPEN = 1; // Serial Port Enabled
RCSTAbits.RX9 = 0; // 8 bit reception
TXSTAbits.TX9 = 0; // 8-bit transmission
RCSTAbits.CREN = 1; // Receiver enabled
TXSTAbits.TXEN = 1; // Transmitter enabled
PIE1bits.TXIE = 0; // Enable USART Transmitter interrupt
PIE1bits.RCIE = 1; // Enable USART Receive interrupt
while(PIR1bits.RCIF){
writeRXIN(RX());
}
INTCONbits.PEIE = 1; // Enable peripheral interrupts
INTCONbits.GIE = 1; // Enable global interrupts
while(1){
while(RXIN > 0){
TX(RXIN);
_PIN_DIMPWMPIN_ = 1;
__delay_ms(100);
_PIN_DIMPWMPIN_ = 0;
__delay_ms(100);
RXIN--;
}
}
// infinite loop
// never leave this loop
return (EXIT_SUCCESS);
} // end main
void interrupt ISR(void){
if(PIE1bits.RCIE && PIR1bits.RCIF){ // handle RX pin interrupts
while(PIR1bits.RCIF){
writeRXIN(RX());
}
if(RCSTAbits.FERR){
flagRXFramingError = 1;
SPEN = 0;
SPEN = 1;
}
if(RCSTAbits.OERR){
flagRXOverrunError = 1;
CREN = 0;
CREN = 1;
}
} // end RX pin interrupt handlers
} // end ISRs*/
I'm currently working on a robot as an intern and must choose replacement drivers for the motors. The position information of the axis are given by analog pot. I do have 3 drivers by technosoft that needs a rotary encoder (quadrature) information to do their regulation job.
I was thinking about converting this analog signal into the right quadrature signal to make it work.
The way I designed it is a pic18 sampling the pot value at 150hz, subtracting the previous value to the current one to have an idea (a kind of derivation) of the speed. It generates an absolute value of the speed and a direction signal whose regulate the rate of change of a state machine with the 4 states of the quadrature encoder. I finally send these signals to the 2 outputs.
My questions are the following.
Is it feasible. Or is there a clever way of doing so ? Or even a dedicated chip that can do the job? I searched the web to find someone who would have already done something similar but found nothing.
I've spend my 2 last days to code this solution & debug it without success...
On the scope, the quadrature signal is there but it behaves with no real logic. Changing really fast or slowly whether I move or don't move the pot.
Here's my code
#include <p18f4685.h>
#include <stdlib.h>
#include <stdio.h>
#include <delays.h>
// ----------------------
// Configuration Hardware
// ----------------------
#pragma config OSC = HSPLL
#pragma config MCLRE = ON, PWRT = OFF
#pragma config DEBUG = ON, LVP = OFF
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config BOREN = OFF
#pragma config WDT = OFF
#pragma config XINST = OFF
#pragma code
// Variables
unsigned int position_t0=0;
unsigned int position_t1=0;
signed int speed=0;
unsigned int speed_abs=0;
int direction=0; // si 0 cw, si 1 ccw
unsigned int count_1 = 0;
unsigned int state_out = 0;
//proto fonctions
void setup(void);
void get_pot(void);
void set_out(void);
void low_isr(void);
void high_isr(void);
int abval(int);
void main(void)
{
setup(); //initialisation
get_pot();
LATE = 0b00000000;
while(1)
{
}
}
void setup (void)
{
/*config timers*/
T0CON = 0b11000101; // timer on, 8bits, internal clock, prescaler on + value 1/64 (152 interruptions par seconde)
// data acquisition interrup
T2CON = 0b00111100; // output moditication loop timer 8bits 1/8postscale 1200 interrupt/second
PR2 = 0b00001111;
/*config adc*/
ADCON1 = 0b00001010; // A0->A4 analo + VDD+GND reference
ADCON2 = 0b10111000; // A/D acq time (ADCON2) 20TAD, A/D conversion clock (ADCON2)
// right justified
ADCON0 = 0b00000001; // Turn on A/D module (ADCON0) + channel select
/*config des pins*/
// TRISA = 0b00011111; // 5 entrées analogiques + 3 digitales
// TRISB = 0b01001100; // sorties pour la version finale
TRISE = 0b00000000; // sorties pour la version test
// PORTA = 0b00000000; // Clear A
PORTE = 0b00000000; // clear E
/*config interruptions*/
RCONbits.IPEN = 1; // priority enabled
INTCON = 0b11100000; // enable les interruption hautes et basses, Timer0 interrupt On
INTCON2 = 0b10000100; // Pull up désactivés +timer0 high(acquisition vitesse)
PIE1bits.TMR2IE = 1; // enable interrupt timer2
IPR1bits.TMR2IP = 0; // timer 2 en priorité basse(mise à jour des pins)
}
void get_pot (void) //get the value of the pot and computes the data
{
ADCON0bits.CHS1 = 0;
ADCON0bits.CHS0 = 0;
ADCON0bits.GO = 1;
while(ADCON0bits.GO==1){}
position_t1 = ADRESH*256+ADRESL;
speed = position_t1 - position_t0;
if(speed<0) direction = 1;
else direction = 0;
speed_abs = abval(speed);
position_t0 = position_t1;
}
void set_out (void) //set the output according the speed and direction
{
if(speed_abs>1)
{
count_1++;
if(count_1>=(1023-speed_abs)/4) //counter that makes the output change more or less faster
{
if(direction==1)
{
switch(state_out)
{
case 0:
{
LATE = 0b00000000;
state_out++;
}
break;
case 1:
{
LATE = 0b00000001;
state_out++;
}
break;
case 2:
{
LATE = 0b00000011;
state_out++;
}
break;
case 3:
{
LATE = 0b00000010;
state_out=0;
}
break;
}
}
else if(direction==0)
{
switch(state_out)
{
case 0:
{
LATE = 0b00000000;
state_out=3;
}
break;
case 1:
{
LATE = 0b00000001;
state_out--;
}
break;
case 2:
{
LATE = 0b00000011;
state_out--;
}
break;
case 3:
{
LATE = 0b00000010;
state_out--;
}
break;
}
}
count_1=0;
}
}
}
int abval(int val)
{
return (val<0 ? (-val) : val);
}
#pragma interrupt high_isr
void high_isr (void) //interruption de récupération des adc
{
if(INTCONbits.TMR0IF==1)
{
get_pot();
INTCONbits.TMR0IF=0;
}
}
#pragma interruptlow low_isr
void low_isr (void) //interruption de mise à jour des sorties
{
if(PIR1bits.TMR2IF==1)
{
set_out();
PIR1bits.TMR2IF=0;
}
}
/*
*********************************************************************************************************
* Interupt Vectors
*********************************************************************************************************
*/
#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm goto low_isr _endasm
}
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm goto high_isr _endasm
}
Part of the code comments are in french, i translated the important ones.
Do you see any obvious mistakes/wrong ways of coding. Do you have any advices of "where to search" or what to watch ?
Thanks by advance for your help !
Nicolas