#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <string.h>
#include <stdint.h>
#include "config.h"
#include "Uart.h"
#define _XTAL_FREQ 20000000
#define RS RC0
#define EN RC1
#define D4 RC2
#define D5 RC3
#define D6 RC4
#define D7 RC5
/*
*
*/
void Lcd_Port(char a)
{
if(a & 1)
D4 = 1;
else
D4 = 0;
if(a & 2)
D5 = 1;
else
D5 = 0;
if(a & 4)
D6 = 1;
else
D6 = 0;
if(a & 8)
D7 = 1;
else
D7 = 0;
}
void Lcd_Cmd(char a)
{
RS = 0; // => RS = 0
Lcd_Port(a);
EN = 1; // => E = 1
__delay_ms(4);
EN = 0; // => E = 0
}
int Lcd_Clear()
{
Lcd_Cmd(0);
Lcd_Cmd(1);
}
void Lcd_Set_Cursor(char a, char b)
{
char temp,z,y;
if(a == 1)
{
temp = 0x80 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
else if(a == 2)
{
temp = 0xC0 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
}
void Lcd_Init()
{
Lcd_Port(0x00); // clear latches before enabling TRIS bits
__delay_ms(20);
Lcd_Cmd(0x03);
__delay_ms(5);
Lcd_Cmd(0x03);
__delay_ms(11);
Lcd_Cmd(0x03);
/////////////////////////////////////////////////////
Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
Lcd_Cmd(0x02);
Lcd_Cmd(0x08);//Select Row 1
Lcd_Cmd(0x00);//Clear Row 1 Display
Lcd_Cmd(0x0C);//Select Row 2
Lcd_Cmd(0x00);//Clear Row 2 Display
Lcd_Cmd(0x06);
}
void Lcd_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
RS = 1; // => RS = 1
Lcd_Port(y>>4); //Data transfer
EN = 1;
__delay_us(40);
EN = 0;
Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0;
}
void Lcd_Write_String(char *a)
{
int i;
for(i=0;a[i]!='\0';i++)
Lcd_Write_Char(a[i]);
}
void Lcd_Shift_Right()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}
void Lcd_Shift_Left()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}
int main(int argc, char** argv) {
OSCCONbits.IRCF = 0b1111; //set operating frequency to 31kHz (0b1111) for 16MHz
UART_init();
Lcd_Init();
// ->Setare Pini
//Pini motor DC
ANSELAbits.ANSA0 = 0; //set to digital pin
ANSELAbits.ANSA1 = 0; //set to digital pin
TRISAbits.TRISA0 = 0; //set as output
TRISAbits.TRISA1 = 0; //set as output
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 0;
//Butoane
ANSELAbits.ANSA2 = 0; //set to digital pin
ANSELAbits.ANSA4 = 0; //set to digital pin
ANSELBbits.ANSB4 = 0; //set to digital pin
TRISAbits.TRISA2 = 1; //set as input
TRISAbits.TRISA4 = 1; //set as input
TRISBbits.TRISB4 = 1; //set as input
//LEDuri
//RC6 - RIGHT
//RC6 LEFT
TRISCbits.TRISC6 = 0;
TRISCbits.TRISC7 = 0;
//Set as digital
ANSELCbits.ANSC6 = 0;
ANSELCbits.ANSC7 = 0;
//Folosire LCD
TRISCbits.TRISC0 = 0; //set as output
TRISCbits.TRISC1 = 0; //set as output
TRISCbits.TRISC2 = 0; //set as output
TRISCbits.TRISC3 = 0; //set as output
TRISCbits.TRISC4 = 0; //set as output
TRISCbits.TRISC5 = 0; //set as output
//pull up
//pull upurile
OPTION_REGbits.nWPUEN = 0;
WPUAbits.WPUA2 = 1;
WPUAbits.WPUA4 = 1;
WPUAbits.WPUA0 = 1;
WPUAbits.WPUA1 = 0;
WPUAbits.WPUA3 = 0;
WPUAbits.WPUA5 = 0;
WPUBbits.WPUB4 = 1;
char introducere;
UART_write_string("1. Move to right ");
UART_write('\r');
UART_write_string("2. Move to left");
UART_write('\r');
UART_write_string("4. Stop UART");
UART_write('\r');
PORTCbits.RC6 = 0;
PORTCbits.RC7 = 0;
while(1){
introducere = UART_read();
if (introducere == '1'){
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 0;
PORTCbits.RC6 = 1;
PORTCbits.RC7 = 0;
Lcd_Clear();
Lcd_Set_Cursor(1,1); //Go to the first line
Lcd_Write_String("helo"); //Display String
}
if (introducere == '2' ){
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 1;
PORTCbits.RC6 = 0;
PORTCbits.RC7 = 1;
}
if(PORTAbits.RA2 == 0){ //Right
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 0;
PORTCbits.RC6 = 1;
PORTCbits.RC7 = 0;
}
if(PORTAbits.RA4 == 0){ //left
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 1;
}
if(introducere =='4'){
CREN = 0; //disable receiver
UART_write('\r');
UART_write_string("disable UART!");
UART_write('\r');
}
if(PORTBbits.RB4 == 0){
CREN = 1; //enable receiver
UART_write('\r');
UART_write_string("enable UART!");
UART_write('\r');
}
}
return (EXIT_SUCCESS);
}
The purpose of the project is to create a Dc motor which when we press 1 to rotate to the right and display on the LCD "rotated right", and if we press 2 to rotate to the left and display on the LCD "rotate left".
Used: pic16f1828
LCD: LM016L
I connected: RS (LCD) -> RC0 (pic), EN -> RC1, D4 -> RC2, D5 -> RC3, D6 -> RC4, D7 -> RC5
The program works well, the only problem I have is the fact that when I press "1" I want HELO to appear on LCD (it doesn't matter the arrangement). Till now it does not appear on LCD, is not just about HELLo, nothing is displayed, I can only see that it starts, I don't understand where the problem is.
Your implementation for writing to the HD44780 using a 4-bit parallel interface is wrong.
This is a complete, builds with MPLABX v5.50 and XC8 v2.32, demo that does display "Hello" on line 1 of the LCD module:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F1828
* Compiler: XC8 v2.32
* IDE: MPLABX v5.50
*
* Created on January 23, 2022, 11:27 AM
*
* PIC16F1828
* +-----------:_:-----------+
* VDD -> : 1 VDD VSS 20 : <- VSS
* RA5 <> : 2 OSC2 PGD 19 : <> RA0 ICD_PGD
* RA4 <> : 3 OSC1 PGC 18 : <> RA1 ICD_PGC/D5
* ICD_VPP RA3 -> : 4 VPP/MCLRn 17 : <> RA2
* LCD_D7 RC5 <> : 5 16 : <> RC0 LCD_RS
* LCD_D6 RC4 <> : 6 15 : <> RC1 LCD_EN
* LCD_D5 RC3 <> : 7 14 : <> RC2 LCD_D4
* RC6 <> : 8 13 : <> RB4
* RC7 <> : 9 12 : <> RB5
* RB7 <> : 10 11 : <> RB6
* +-------------------------+
* DIP-20
*
* Description:
*
* See: https://stackoverflow.com/questions/70800375/why-lcd-does-not-display-anything
*/
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#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 = OFF // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#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 = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
/*
* Tell compiler what we intend to set the system oscillator frequency as.
*/
#define _XTAL_FREQ (16000000UL)
#include <xc.h>
#include <stdio.h>
/* Define the LCD interface and character size */
#define LCD_FORMAT (FOUR_BIT & LINES_5X7)
/* Define the LCD port pins */
#define LCD_DATA_BITS_MASK 0x3C
#define LCD_PORT_OUT LATC
#define LCD_PORT_DIR TRISC
#define LCD_RS_PIN LATCbits.LATC0
#define LCD_EN_PIN LATCbits.LATC1
#define LCD_D4_PIN LATCbits.LATC2
#define LCD_D5_PIN LATCbits.LATC3
#define LCD_D6_PIN LATCbits.LATC4
#define LCD_D7_PIN LATCbits.LATC5
#define LCD_RS_PIN_DIR TRISCbits.TRISC0
#define LCD_EN_PIN_DIR TRISCbits.TRISC1
#define LCD_D4_DIR TRISCbits.TRISC2
#define LCD_D5_DIR TRISCbits.TRISC3
#define LCD_D6_DIR TRISCbits.TRISC4
#define LCD_D7_DIR TRISCbits.TRISC5
/* Clear display command */
#define CLEAR_DISPLAY 0b00000001
/* Return home command */
#define RETURN_HOME 0b00000010
/* Display ON/OFF Control defines */
#define DON 0b00001111 /* Display on */
#define DOFF 0b00001011 /* Display off */
#define CURSOR_ON 0b00001111 /* Cursor on */
#define CURSOR_OFF 0b00001101 /* Cursor off */
#define BLINK_ON 0b00001111 /* Cursor Blink */
#define BLINK_OFF 0b00001110 /* Cursor No Blink */
/* Cursor or Display Shift defines */
#define SHIFT_CUR_LEFT 0b00010011 /* Cursor shifts to the left */
#define SHIFT_CUR_RIGHT 0b00010111 /* Cursor shifts to the right */
#define SHIFT_DISP_LEFT 0b00011011 /* Display shifts to the left */
#define SHIFT_DISP_RIGHT 0b00011111 /* Display shifts to the right */
/* Function Set defines */
#define FOUR_BIT 0b00101111 /* 4-bit Interface */
#define EIGHT_BIT 0b00111111 /* 8-bit Interface */
#define LINE_5X7 0b00110011 /* 5x7 characters, single line */
#define LINE_5X10 0b00110111 /* 5x10 characters */
#define LINES_5X7 0b00111011 /* 5x7 characters, multiple line */
/* Start address of each line */
#define LINE_ONE 0x00
#define LINE_TWO 0x40
static void LCD_E_Pulse(void)
{
LCD_EN_PIN = 1;
__delay_us(4);
LCD_EN_PIN = 0;
__delay_us(4);
}
static void LCD_DelayPOR(void)
{
__delay_ms(15);
}
static void LCD_Delay(void)
{
__delay_ms(5);
}
static void LCD_PutByte(unsigned char LCD_Data)
{
LCD_PORT_DIR &= ~LCD_DATA_BITS_MASK; /* make LCD data bits outputs */
/* send first(high) nibble */
LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;
if(LCD_Data & 0x10) LCD_D4_PIN = 1;
if(LCD_Data & 0x20) LCD_D5_PIN = 1;
if(LCD_Data & 0x40) LCD_D6_PIN = 1;
if(LCD_Data & 0x80) LCD_D7_PIN = 1;
LCD_E_Pulse();
/* send second(low) nibble */
LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;
if(LCD_Data & 0x01) LCD_D4_PIN = 1;
if(LCD_Data & 0x02) LCD_D5_PIN = 1;
if(LCD_Data & 0x04) LCD_D6_PIN = 1;
if(LCD_Data & 0x08) LCD_D7_PIN = 1;
LCD_E_Pulse();
LCD_PORT_DIR |= LCD_DATA_BITS_MASK; /* make LCD data bits inputs */
}
void LCD_SetPosition(unsigned char data)
{
LCD_RS_PIN = 0;
LCD_PutByte((unsigned char)(data | 0x80));
__delay_us(40);
}
void LCD_WriteCmd(unsigned char data)
{
LCD_RS_PIN = 0;
LCD_PutByte(data);
__delay_ms(4);
}
void LCD_WriteData(unsigned char data)
{
LCD_RS_PIN = 1;
LCD_PutByte(data);
LCD_RS_PIN = 0;
__delay_us(40);
}
void LCD_Init(void)
{
unsigned char LCD_Data;
LCD_PORT_DIR &= ~LCD_DATA_BITS_MASK; /* make LCD data bits outputs */
LCD_EN_PIN_DIR = 0; /* make LCD Enable strobe an output */
LCD_RS_PIN_DIR = 0; /* make LCD Register select an output */
LCD_EN_PIN = 0; /* set LCD Enable strobe to not active */
LCD_RS_PIN = 0; /* set LCD Register select to command group */
LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK; /* set LCD data bits to zero */
LCD_DelayPOR(); /* wait for LCD power on to complete */
/* Force LCD to 8-bit mode */
LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK; /* set LCD data bits to zero */
LCD_D4_PIN = 1;
LCD_D5_PIN = 1;
LCD_E_Pulse();
LCD_Delay();
LCD_E_Pulse();
LCD_Delay();
LCD_E_Pulse();
LCD_Delay();
/* Set LCD to 4-bit mode */
LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK; /* set LCD data bits to zero */
LCD_D5_PIN = 1;
LCD_E_Pulse();
LCD_Delay();
/* Initialize LCD mode */
LCD_WriteCmd(LCD_FORMAT);
/* Turn on display, Setup cursor and blinking */
LCD_WriteCmd(DOFF & CURSOR_OFF & BLINK_OFF);
LCD_WriteCmd(DON & CURSOR_OFF & BLINK_OFF);
LCD_WriteCmd(CLEAR_DISPLAY);
LCD_WriteCmd(SHIFT_CUR_LEFT);
/* Set first position on line one, left most character */
LCD_SetPosition(LINE_ONE);
}
/*
* Hook for printf
*/
void putch(char txData)
{
LCD_WriteData(txData);
}
/*
* Main application
*/
void main(void)
{
OSCCON = 0x7A; //set operating frequency to 16MHz
ANSELA = 0;
ANSELB = 0;
ANSELC = 0;
//pull up
OPTION_REGbits.nWPUEN = 0;
WPUAbits.WPUA2 = 1;
WPUAbits.WPUA4 = 1;
WPUAbits.WPUA0 = 1;
WPUAbits.WPUA1 = 0;
WPUAbits.WPUA3 = 0;
WPUAbits.WPUA5 = 0;
LCD_Init();
__delay_ms(100);
LCD_SetPosition(LINE_ONE);
printf("Hello");
/*
* Application loop
*/
for(;;)
{
}
}
Related
Here is the code,
I dont understand how to change it to a 10-bit ADC.
my guess is something along the line of 16-bits and just ignore the last 6, but i have no clue .
If someone can offer advice on how to change it, great.
Im really lost.
I've read somethings about this, but I've just gotten more confused the more I read.
Here is the led arrangement
Any other information needed just ask
#include <xc.h>
/* Configuration Word */
#pragma config FOSC = INTOSCIO// Clock
#pragma config WDTE = OFF //
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown Out Detect (BOR disabled)
#pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
// CONFIG --- Configuration Word --- END
void PORTA_init(void);
void ADC_Disp(void);
void Delay_LED_On(void);
int ADC_Value = 0;
const char PORTA_Value[8] = {
0b010000, // D0
0b100000, // D1
0b010000, // D2
0b000100, // D3
0b100000, // D4
0b000100, // D5
0b000100, // D6
0b000010}; // D7
const char TRISA_Value[8] = {
0b001111, // D0
0b001111, // D1
0b101011, // D2
0b101011, // D3
0b011011, // D4
0b011011, // D5
0b111001, // D6
0b111001}; // D7
main()
{
PORTA_init();
ANSEL = 1; // Just RA0 is an Analog Input
TRISA0 = 1; // Corresponding TRIS bit is set as input
ADCON0 = 0b00000001; // Turn on the ADC
// Bit 7 - Left Justified Sample
// Bit 6 - Use VDD
// Bit 4:2 - Channel 0
// Bit 1 - Do not Start
// Bit 0 - Turn on ADC
ADCON1 = 0b00010000; // Select the Clock as Fosc/8
ADC_Disp();
GO_DONE = 1; // Start A/D Conversion
while(1 == 1) // Loop Forever
{
if (GO_DONE == 0) // Is A/D Conversion complete?
{ ADC_Disp(); // Display A/D Conversion Results
ADC_Value = ADRESH; // Get new A/D value
GO_DONE = 1; // Start the next A/D Conversion
}
else // A/D Conversion still in progress
ADC_Disp();
}
}
/******** END OF main ROUTINE ***************************/
void PORTA_init(void)
{
PORTA = 0; // All PORTA Pins are low
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
return;
}
/******** END OF PORTA_init ****************************/
/********************************************************
* Function: ADC_Disp
*
* Description: Displays the value of A/D Conversion on D0 - D7
*
* Notes:
*
*
*
* Returns: None
*
********************************************************/
void ADC_Disp(void)
{
int i;
for (i = 0; i < 8; i++ )
{ // Loop through Each of the 8 LEDS
Delay_LED_On(); // Allows time for individual LEDs to light
if ((ADC_Value & (1 << i)) == 0)
PORTA = 0;
else
PORTA = PORTA_Value[i];
TRISA = TRISA_Value[i];
} //
return;
}
/******** END OF ADC_Disp *************************/
void Delay_LED_On(void)
{
int j;
for (j = 0; j < 60; j++); // Display "On" Loop
return;
}
/******** END OF Delay_LED_On *************************/
By default ADC is configured to give left justified results(ADFM=0). The lower 8 bits are in ADRESH and the upper 2 bits are stored in ADRESL. You can read both addresses into a 16 bit variable and discard the upper 6 bits.
uint16_t ADC_Value = ( (ADRESH << 8) | ADRESL ) >> 6;
Pretty easy:
use a right justified result
ADCON0 = 0b10000001; // Turn on the ADC
// Bit 7 - Right Justified Sample
// Bit 6 - Use VDD
// Bit 4:2 - Channel 0
// Bit 1 - Do not Start
// Bit 0 - Turn on ADC
And then a 16 Bit result:
uint16_t ADC_result;
ADC_result = (uint16_t)(ADRESH <<8) + ADRESL;
Know you 10 Bit result is in the lower 10 Bits of ADC_result.
Another issue in your code: look at your braces and indent your code carefully.
This won't work:
if ((ADC_Value & (1 << i)) == 0)
PORTA = 0;
else
PORTA = PORTA_Value[i];
TRISA = TRISA_Value[i];
One way of obtaining 10 bits out of an 8 bits ADC is : Four samples of ADC data of 8 bits can be averaged and then multiplied by 4 to get a 10 bits precision data. So overall conversion rate of 10 bit data seems like 1/4th of the conversion rate of 8 bits ADC.
This code will display 10-bits of the ADC value in 10 Charlieplexed LEDs:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F684
* Compiler: XC8 v2.20
* IDE: MPLABX v5.25
*
* Description:
*
* Display the upper 10-bits of the ADC conversion
* from analog input from RA0 on 12 charlieplexed
* LEDs connected to outputs RA1,RA2,RA4,RA5.
*
* PIC16F684
* +------------:_:------------+
* GND -> 1 : VDD VSS : 14 <- 5v0
* DRV5 <> 2 : RA5/T1CKI PGD/AN0/RA0 : 13 <> POT
* DRV4 <> 3 : RA4/AN3 PGC/AN1/RA1 : 12 <> DRV1
* VPP -> 4 : RA3/VPP AN2/RA2 : 11 <> DRV2
* <> 5 : RC5/CPP1 AN4/RC0 : 10 <>
* <> 6 : RC4/C2OUT AN5/RC1 : 9 <>
* <> 7 : RC3/AN7 AN6 RC2 : 8 <>
* +---------------------------:
* DIP-14
*
* 150 OHM
* DRV4 ----/\/\/\-------+---------+---------+---------+-----------------------------+---------+
* : : : : : :
* : : : : : :
* --- --- --- --- : :
* LED1 / \ LED0 \ / LED3 / \ LED2 \ / : :
* --- --- --- --- : :
* : : : : : :
* 150 OHM : : : : : :
* DRV5 ----/\/\/\-------+---------+-------- : ------- : --------+---------+ : :
* : : : : : : : :
* : : : : : : : :
* --- --- : : : : --- ---
* LED5 / \ LED4 \ / : : : : LED11 / \ LED10 \ /
* --- --- : : : : --- ---
* : : : : : : : :
* 150 OHM : : : : : : : :
* DRV2 ----/\/\/\-------+---------+---------+---------+ : : : :
* : : : : : :
* : : : : : :
* --- --- --- --- : :
* LED7 / \ LED6 \ / LED9 / \ LED8 \ / : :
* --- --- --- --- : :
* : : : : : :
* 150 OHM : : : : : :
* DRV1 ----/\/\/\-------+---------+-----------------------------+---------+---------+---------+
*
*
* POT -----/\/\/\--+-------+
* 1K : :
* : --- 1nF
* : ---
* v :
* 5v0 ----------/\/\/\-----+---- GND
* 10K
*
*
* Notes:
* Charlieplexing, see https://en.wikipedia.org/wiki/Charlieplexing
*
* Created on July 13, 2019, 6:09 PM
*/
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ (8000000ul)
/*
* Global data
*/
volatile uint8_t gLEDs_0_to_7;
volatile uint8_t gLEDs_8_to_11;
volatile uint8_t gTicks;
void main(void)
{
/*
* Initialize this PIC
*/
INTCON = 0;
OSCCON = 0x70; /* Select 8MHz system oscillator */
__delay_ms(500); /* Give ISCP device programming tool a chance to get the PICs attention */
TRISA = 0xFF;
TRISC = 0x00;
ANSEL = 0;
OPTION_REG = 0b11000010; /* TIMER0 clock = FOSC/4, prescale 1:8 */
PORTA = 0;
PORTC = 0;
CMCON0 = 7;
TMR0 = 0;
TMR0IF = 0;
TMR0IE = 1;
gLEDs_0_to_7 = 0b00000000;
gLEDs_8_to_11 = 0b00000000;
gTicks = 0;
GIE = 1;
/*
* Initialize ADC on channel 0
*/
ADCON0 = 0;
ADCON1 = 0;
TRISAbits.TRISA0 = 1; /* Make RA0 an input */
ANSELbits.ANS0 = 1; /* Enable AN0 on the RA0 input */
ADCON1bits.ADCS = 0b101; /* Select FOSC/16 as ADC clock source */
ADCON0bits.CHS = 0; /* Select AN0 as ADC input */
ADCON0bits.ADFM = 0; /* Select left justified data */
ADCON0bits.VCFG = 0; /* Select VDD as VREF source */
ADCON0bits.ADON = 1; /* Turn on ADC */
/*
* This is the application loop.
*
* Display 8-bit ADC value in charlieplexed LEDs
*/
while(1)
{
ADCON0bits.GO = 1; /* Start an ADC conversion */
while(ADCON0bits.GO); /* Wait for ADC conversion to finish */
gLEDs_0_to_7 = ADRESH; /* Put High 8-bits of ADC value in LED7 to LED0 */
/* Put Low 2-bits of ADC value in LED8 to LED9 */
gLEDs_8_to_11 = (gLEDs_8_to_11 & ~3) | (ADRESL >> 6);
/* Flash LED D11 to show application is running */
if(!gTicks)
{
gTicks = 250;
gLEDs_8_to_11 ^= 0x08;
}
}
}
/*
* Interrupt handlers
*/
void __interrupt() ISR_handler(void)
{
static uint8_t Timer0Ticks = 0;
static uint8_t State = 8;
uint8_t OutBits, HighBits;
if (TMR0IE && TMR0IF) { /* TIMER0 asserts and interrupt every 1.024 milliseconds */
TMR0IF=0;
if(gTicks != 0) gTicks--;
if (Timer0Ticks == 0) { /* Select another LED every second TIMER0 interrupt */
Timer0Ticks = 1; /* to make LEDs a little brighter make this number larger until you don't like the flickering */
OutBits = 0b00000000;
HighBits = 0b00000000;
switch (--State)
{
case 11:
if (gLEDs_8_to_11 & 0x08)
{
HighBits |= (1 << 1); /* Drive LED11, DRV4=L DRV1=H */
OutBits = ~((1<<1)|(1<<4));
}
break;
case 10:
if (gLEDs_8_to_11 & 0x04)
{
HighBits |= (1 << 4); /* Drive LED10, DRV4=H DRV1=L */
OutBits = ~((1<<1)|(1<<4));
}
break;
case 9:
if (gLEDs_8_to_11 & 0x02)
{
HighBits |= (1 << 1); /* Drive LED9, DRV1=H DRV5=L */
OutBits = ~((1<<1)|(1<<5));
}
break;
case 8:
if (gLEDs_8_to_11 & 0x01)
{
HighBits |= (1 << 5); /* Drive LED8, DRV1=L DRV5=H */
OutBits = ~((1<<1)|(1<<5));
}
break;
case 7:
if (gLEDs_0_to_7 & 0x80)
{
HighBits |= (1 << 1); /* Drive LED7, DRV1=H DRV2=L */
OutBits = ~((1<<1)|(1<<2));
}
break;
case 6:
if (gLEDs_0_to_7 & 0x40)
{
HighBits |= (1 << 2); /* Drive LED6, DRV1=L DRV2=H */
OutBits = ~((1<<1)|(1<<2));
}
break;
case 5:
if (gLEDs_0_to_7 & 0x20)
{
HighBits |= (1 << 2); /* Drive LED5, DRV5=L DRV2=H */
OutBits = ~((1<<5)|(1<<2));
}
break;
case 4:
if (gLEDs_0_to_7 & 0x10)
{
HighBits |= (1 << 5); /* Drive LED4, DRV5=H DRV2=L */
OutBits = ~((1<<5)|(1<<2));
}
break;
case 3:
if (gLEDs_0_to_7 & 0x08)
{
HighBits |= (1 << 2); /* Drive LED3, DRV4=L DRV2=H */
OutBits = ~((1<<4)|(1<<2));
}
break;
case 2:
if (gLEDs_0_to_7 & 0x04)
{
HighBits |= (1 << 4); /* Drive LED2, DRV4=H DRV2=L */
OutBits = ~((1<<4)|(1<<2));
}
break;
case 1:
if (gLEDs_0_to_7 & 0x02)
{
HighBits |= (1 << 5); /* Drive LED1, DRV4=L DRV5=H */
OutBits = ~((1<<4)|(1<<5));
}
break;
default:
if (gLEDs_0_to_7 & 0x01)
{
HighBits |= (1 << 4); /* Drive LED0, DRV4=H DRV5=L */
OutBits = ~((1<<4)|(1<<5));
}
State = 12;
}
TRISA |= ((1<<5)|(1<<4)|(1<<2)|(1<<1)); /* Turn off all LED output drivers */
if (OutBits)
{
PORTA &= OutBits; /* Set both LED drivers to low */
TRISA &= OutBits; /* Turn on LED output drivers */
PORTA |= HighBits; /* Turn on just one of the two LEDs */
}
}
else
{
Timer0Ticks--;
}
}
}
Hope you get a good grade for your home work.
I'm trying to convert this code to be able to generate random numbers 1-56.
I would understand, but because the program has to switch back and forth to be able to show both digits, I'm confused.
I know in some respect, I can use rand() to choose.
I will eventually use this code in junction with an lcd screen to display the numbers as well as the dual seven segment display, but for now, just trying to figure out to program a PIC16F684 to generate the random number on the dua84l seven seg display
Below is the circuit and code.
Not included in the diagram, but in the code is RA3 & RA4 have buttons that clear the display or generate the next digit.
The program supplied displays 00-0xFF as a button gets pushed. It may be easier to rewrite the program, but I just dont understand it
#include <xc.h>
/*
*
*
* 6/30/2020
/******************************************/
/* ------------------------------------------- */
/* Software/Hardware Interface: */
/* ------------------------------------------- */
/* */
/* Select Right Digit using >> RA0 */
/* Select Left Digit using >> RA1 */
/* */
/* Segment a >> RA5 */
/* Segment b >> RC5 */
/* Segment c >> RC4 */
/* Segment d >> RC3 */
/* Segment e >> RC2 */
/* Segment f >> RC1 */
/* Segment g >> RC0 */
/* ------------------------------------------- */
void PORTA_init(void)
{
PORTA = 0; // All PORTA Pins are low
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
//TRISA = 0b001111; // RA4 and 5 are outputs; RA0,1,2, and 3 are input
return;
}
/******** END OF PORTA_init ****************************/
void delay_routine(void)
{
int i, j;
for (i = 0; i<2000; i++);
for (j = 0; j <2000;j++);
return;
}
/******** END OF delay_20ms *************************/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END
int i, j;
int DisplayValue, DisplayLED;
const char LEDDigit[] = {
0b0000001, // "0"
0b1001111, // "1"
0b0010010, // "2"
0b0000110, // "3"
0b1001100, // "4"
0b0100100, // "5"
0b0100000, // "6"
0b0001111, // "7"
0b0000000, // "8"
0b0001100, // "9"
0b0001000, // "A"
0b0000000, // "b"
0b0110001, // "C"
0b0000001, // "d"
0b0110000, // "E"
0b0111000
}; // "F"
main()
{
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
TRISA = 0b011101; // RA5 and RA1 are outputs
TRISC = 0b000000;
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
while(1 == 1) // Loop Forever
{
if (0 == DisplayLED) // True, then display right digit
{
RA5 = LEDDigit[DisplayValue & 0x0F] >> 6;
// Clears display bits 4 - 7 of DisplayValue,
// then selects bit 7 of LEDDigit
PORTC = LEDDigit[DisplayValue & 0x0F] & 0x03F;
// clears display bits 4 - 7 of DisplayValue,
// then selects bits 0 - 6 of LEDDigit
}
else
{
RA5 = LEDDigit[(DisplayValue >> 4) & 0x0F] >> 6;
PORTC = LEDDigit[(DisplayValue >> 4) & 0x0F] & 0x03F;
} //
TRISA = TRISA ^ 0b000011; // Swap Left/Right (RA0 and RA1)
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
NOP(); // Used for 10 ms Timing
for (i = 0; i < 30; i++);//10ms Delay Loop
NOP(); // Used for 10 ms Timing
if (RA3 == 0)
{
delay_routine();
DisplayValue++; // Increment the Counter
delay_routine();
} //
if (RA4 == 0)
{
delay_routine();
DisplayValue=0;
delay_routine();
}
}
}
#tjpplay,
The code you posted has some subtle issues and a failure to alternate the digit driver enables.
Your method to detect a button press disrupts the digit multiplexer timing and causes flicker.
With the digit drivers connected to the PGC and PGD pins used for In-Circuit-Serial-Programmer(ICSP) makes in circuit programming difficult. In-Circuit-Debug(ICD) will not work with this implementation.
The code avoids the Read-Modify-Write(RMW) trap for new players by only using 8-bit writes to the PORTA and PORTC registers.
Using syntax that allows the C compiler to do single bit sets and clears can have a RMW issue for controllers like the PIC16F684 especially when driving LED directly.
I think that this code may work with your hardware:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F684
* Compiler: XC8 v2.20
* IDE: MPLABX v5.25
*
* Description:
*
* Created on July 21, 2020, 3:45 PM
*
* PIC16F684
* +------------:_:------------+
* GND -> 1 : VDD VSS : 14 <- 5v0
* SEG_a_DRIVE <> 2 : RA5/T1CKI PGD/AN0/RA0 : 13 <> DIGIT_DRIVE_2
* SW2 <> 3 : RA4/AN3 PGC/AN1/RA1 : 12 <> DIGIT_DRIVE_1
* SW1 -> 4 : RA3/VPP AN2/RA2 : 11 <>
* SEG_b_DRIVE <> 5 : RC5/CPP1 AN4/RC0 : 10 <> SEG_g_DRIVE
* SEG_c_DRIVE <> 6 : RC4/C2OUT AN5/RC1 : 9 <> SEG_f_DRIVE
* SEG_d_DRIVE <> 7 : RC3/AN7 AN6 RC2 : 8 <> SEG_e_DRIVE
* +---------------------------:
* DIP-14
*/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END
#include <xc.h>
#include <stdlib.h>
/* Oscillator frequency we will select with the OSCCON register */
#define _XTAL_FREQ (4000000ul)
/*
* Segment locations
* of an LED display
* ---a---
* : :
* f b
* : :
* ---g---
* : :
* e c
* : :
* ---d---
*/
const unsigned char LEDDigit[] = {
// abcdefg, Segment on = 0
0b00000001, // "0"
0b01001111, // "1"
0b00010010, // "2"
0b00000110, // "3"
0b01001100, // "4"
0b00100100, // "5"
0b00100000, // "6"
0b00001111, // "7"
0b00000000, // "8"
0b00001100, // "9"
0b00001000, // "A"
0b01100000, // "b"
0b00110001, // "C"
0b01000010, // "d"
0b00110000, // "E"
0b00111000 // "F"
};
void main(void)
{
unsigned char DisplayValue, DisplayLED, DigitSegments;
unsigned char LoopCount;
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
__delay_ms(500); // wait for ICD before making PGC and PGD outputs;
TRISA = 0b011100; // RA5, RA1, RA0 are outputs
TRISC = 0b000000;
OPTION_REGbits.nRAPU = 0; // Enable weak pull-up on PORTA
WPUA = 0; // Turn off all pull-ups
WPUAbits.WPUA4 = 1; // Turn on RA4 pull-up
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
LoopCount = 0;
for(;;)
{
PORTC = 0xFF; // turn off all segment drivers
PORTA = 0xFF; // and digit drivers
if (1 == (DisplayLED & 1))
{
DigitSegments = LEDDigit[(DisplayValue >> 4) & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111110; // turn on Digit driver 2
}
else
{
PORTA = 0b011110; // turn on Digit driver 2 and SEG_a_DRIVER
}
}
else
{
DigitSegments = LEDDigit[DisplayValue & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111101; // turn on Digit driver 1
}
else
{
PORTA = 0b011101; // turn on Digit driver 1 and SEG_a_DRIVER
}
}
PORTC = DigitSegments; // turn on segment drivers b to g
DisplayLED++; // select next digit
__delay_ms(10); // Show digit for 10 milliseconds
if(0 == PORTAbits.RA3) // is SW1 pressed?
{
LoopCount++;
if(LoopCount == 1)
{
DisplayValue++; // Increment display value every 500 milliseconds
}
if(LoopCount >= 50)
{
LoopCount = 0;
}
}
else
{
LoopCount = 0;
}
if(0 == PORTAbits.RA4) // is SW2 pressed?
{
DisplayValue = 0; // Reset display value to zero
LoopCount = 0;
}
}
}
This is how I would chnage the above code to produce the random numbers you asked for:
void main(void)
{
unsigned char DisplayValue, DisplayLED, DigitSegments;
unsigned char LoopCount;
unsigned int Temp;
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
__delay_ms(500); // wait for ICD before making PGC and PGD outputs;
TRISA = 0b011100; // RA5, RA1, RA0 are outputs
TRISC = 0b000000;
OPTION_REGbits.nRAPU = 0; // Enable weak pull-up on PORTA
WPUA = 0; // Turn off all pull-ups
WPUAbits.WPUA4 = 1; // Turn on RA4 pull-up
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
LoopCount = 0;
srand(0x1234);
for(;;)
{
PORTC = 0xFF; // turn off all segment drivers
PORTA = 0xFF; // and digit drivers
if (1 == (DisplayLED & 1))
{
DigitSegments = LEDDigit[(DisplayValue >> 4) & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111110; // turn on Digit driver 2
}
else
{
PORTA = 0b011110; // turn on Digit driver 2 and SEG_a_DRIVER
}
}
else
{
DigitSegments = LEDDigit[DisplayValue & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111101; // turn on Digit driver 1
}
else
{
PORTA = 0b011101; // turn on Digit driver 1 and SEG_a_DRIVER
}
}
PORTC = DigitSegments; // turn on segment drivers b to g
DisplayLED++; // select next digit
__delay_ms(10); // Show digit for 10 milliseconds
if(0 == PORTAbits.RA3) // is SW1 pressed?
{
LoopCount++;
if(LoopCount == 1)
{
// Display a new random value every 500 milliseconds
Temp = rand() & 0xFFu; // put random value in range of 0 to 255 and treat is as a fraction in range (0/256) <= value < (255/256)
Temp = (Temp * 56u + 0x100u) >> 8; // Use tricky math to make a random number in the range from 1 to 56
DisplayValue = (Temp / 10u) << 4; // Extract the ten's digit
DisplayValue = DisplayValue | (Temp % 10); // Extract the one's digit
}
if(LoopCount >= 50)
{
LoopCount = 0;
}
}
else
{
LoopCount = 0;
}
if(0 == PORTAbits.RA4) // is SW2 pressed?
{
DisplayValue = 0; // Reset display value to zero
LoopCount = 0;
}
}
}
Your digits are BCD coded(BinaryCodedDecimal), each digit 0-9 is coded in four bits 0000-1001.
DisplayLED toggles between 0 and 1, to select which digit to display, you must ensure you don't update the random value until it have been displayed, actually you should probably update it even more seldom as the display relays on the after glow in the LED and our slow eyes to display an image.
if (DisplayLED == 0) {
uint8_t r = myrand(); // place your favorite random generator here.
DisplayValue = (r/10)<<4|(r%10);
}
Pin 0 and 1 on PortA are flipped by turning them to input and output respectively
TRISA = TRISA ^ 0b000011; // Swap Left/Right (RA0 and RA1)
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
Since the least significant bits in TRISA are initiated as 01 they will alternate when negated only one of them is always an output.
Can someone please help me with this? I have been researching and trying to get this working, but I'm out of luck. All the codes I found online were not working... The output, for now, is 00, 11, 22, 33, ... FF and lop back to 00. How do I separate the first and second digit displays? Like I want it to display from 0 to 255 (00, 01, 02...FF)?
Requirements:
When the circuit is first energized, the seven-segment LEDs will start counting at 0x00.
The duel segment LEDs will count up to 0xFF, increasing by 1 each time. The count MUST BE sequential. It is unacceptable to count 0 to F to 0 on digit 2, then increase digit 1 by 1. The count shall perform like a counter (0x00 to 0x0F then 0x10 etc.).
Once the count reaches 0xFF, the count will start over at 0x00.
The code will contain sufficient delay between incrementing the count so that the count can be visually confirmed that the circuit/code is operating as designed.
The above will occur infinitely, another word, in an endless loop until the device is powered down.
Source code:
#include
void PORTA_init(void)
{
PORTA = 0; // All PORTA Pins are low
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
//TRISA = 0b001111; // RA4 and 5 are outputs; RA0,1,2, and 3 are input
return;
}
/******** END OF PORTA_init ****************************/
/********************************************************
* Notes:
*
* Delay was determined through trial and error
*
* Returns: None
* ********************************************************/
/** Function: main *************************************
*
* Notes:
*
* RA4 - Positive LED Connection for D0
* RA5 - Negative LED Connection for D0
*
* Returns: None -- This routine contains an infinite loop
*
*/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END
int i, j;
int DisplayValue, DisplayLED;
//PLACE LEDDigit ARRAY HERE
const char LEDDigit[] = {
0b0000001, // "0"
0b1001111, // "1"
0b0010010, // "2"
0b0000110, // "3"
0b1001100, // "4"
0b0100100, // "5"
0b0100000, // "6"
0b0001111, // "7"
0b0000000, // "8"
0b0000100, // "9"
0b0001000, // "A"
0b1100000, // "b"
0b0110001, // "C"
0b1000010, // "d"
0b0110000, // "E"
0b0111000}; // "F"
main()
{
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
TRISA = 0b011100;
TRISC = 0b000000;
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
while(1 == 1) // Loop Forever
{
if (0 == DisplayLED) // True, then display right digit
{
RA5 = LEDDigit[DisplayValue & 0x0F] >> 6;
// Clears display bits 4 - 7 of DisplayValue,
// then selects bit 7 of LEDDigit
PORTC = LEDDigit[DisplayValue & 0x0F] & 0x03F;
// clears display bits 4 - 7 of DisplayValue,
// then selects bits 0 - 6 of LEDDigit
}
else
{
RA5 = LEDDigit[(DisplayValue >> 4) & 0x0F] >> 6;
PORTC = LEDDigit[(DisplayValue >> 4) & 0x0F] & 0x03F;
} //
TRISA = TRISA ^ 0b011111; // Swap Left/Right
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
NOP(); // Used for 10 ms Timing
for (i = 0; i < 660; i++); // 10 ms Delay Loop
NOP(); // Used for 10 ms Timing
j = j + 1; // Increment the Counter?
if (25 == j) // 1/4 Second Passed?
{
DisplayValue++; // Increment the Counter
j = 0; // Reset for another 1/4 Second
} //
} //
} //
This is a possible answer to your homework assignment:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F688
* Compiler: XC8 v2.00
*
* PIC16F688
* +------------:_:------------+
* GND -> 1 : VDD VSS : 14 <- 5v0
* SEG_An <> 2 : RA5/T1CKI PGD/AN0/RA0 : 13 <> PGD DIGIT_1n
* <> 3 : RA4/AN3 PGC/AN1/RA1 : 12 <> PGC DIGIT_2n
* VPP -> 4 : RA3/VPP AN2/RA2 : 11 <>
* SEG_Bn <> 5 : RC5/RXD AN4/RC0 : 10 <> SEG_Gn
* SEG_Cn <> 6 : RC4/TXD AN5/RC1 : 9 <> SEG_Fn
* SEG_Dn <> 7 : RC3/AN7 AN6 RC2 : 8 <> SEG_En
* +---------------------------:
* DIP-14
*
* Created on July 7, 2019, 6:56 PM
*/
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ (8000000ul)
const char LEDDigit[] =
{
/* abcdefg _ */
0b00000001, /* | | */
/* |_| */
/* */
0b01001111, /* | */
/* | */
/* _ */
0b00010010, /* _| */
/* |_ */
/* _ */
0b00000110, /* _| */
/* _| */
/* */
0b01001100, /* |_| */
/* | */
/* _ */
0b00100100, /* |_ */
/* _| */
/* _ */
0b00100000, /* |_ */
/* |_| */
/* _ */
0b00001111, /* | */
/* | */
/* _ */
0b00000000, /* |_| */
/* |_| */
/* _ */
0b00001100, /* |_| */
/* | */
/* _ */
0b00001000, /* |_| */
/* | | */
/* */
0b01100000, /* |_ */
/* |_| */
/* _ */
0b00110001, /* | */
/* |_ */
/* */
0b01000010, /* _| */
/* |_| */
/* _ */
0b00110000, /* |_ */
/* |_ */
/* _ */
0b00111000, /* |_ */
/* | */
/* */
0b01111111, /* blank */
/* */
};
volatile uint8_t Digit1Segments;
volatile uint8_t Digit2Segments;
volatile uint8_t Timer0Ticks;
void __interrupt() ISR_handler(void)
{
if (TMR0IE && TMR0IF) { /* TIMER0 asserts and interrupt every 1.024 milliseconds */
TMR0IF=0;
Timer0Ticks++;
if ((Timer0Ticks & 0x0F) == 0) { /* every 16.384 drive a new digit */
if ((TRISA & 3) == 2) {
TRISA |= 3; /* Turn off all digit drivers */
PORTA = 0;
if ((Digit2Segments & (1<<6)) != 0 ) {
PORTA = (1<<5);
}
PORTC = Digit2Segments;
/* Drive digit 2 segments */
TRISA &= ~2;
}
else {
TRISA |= 3;
PORTA = 0;
if ((Digit1Segments & (1<<6)) != 0 ) {
PORTA = (1<<5);
}
PORTC = Digit1Segments;
/* Drive digit 1 segments */
TRISA &= ~1;
}
}
}
}
void main(void) {
uint8_t HexCount;
/*
* Initialize this PIC
*/
INTCON = 0;
OSCCON = 0x70; /* Select 8MHz system oscillator */
__delay_ms(500); /* Give ICSP device programming tool a chance to get the PICs attention */
Digit1Segments = 0b01111111;
Digit2Segments = 0b01111111;
TRISA = 0xDF; /* PORTA bit 5 needs to be an output */
TRISC = 0x00;
ANSEL = 0;
OPTION_REG = 0b11000010; /* TIMER0 clock = FOSC/4, prescale 1:8 */
PORTA = 0;
PORTC = 0;
CMCON0 = 7;
TMR0 = 0;
TMR0IF = 0;
TMR0IE = 1;
GIE = 1;
/*
* This is the application loop.
*
* It counts up one count about every second.
*/
HexCount = 0;
while(1)
{
Digit1Segments = LEDDigit[HexCount & 0x0F];
Digit2Segments = LEDDigit[(HexCount>>4) & 0x0F];
__delay_ms(1000);
HexCount++;
}
}
Only checked using the MPLABX simulator so it may not work in real hardware or in a Proteus simulator.
Warning: I have used concepts that may not have been covered, so if this code works and you hand it in your instructor will know you got it from the internet.
I am using Atmel Studio 6.1 and this is the code that I use, beside this i also got another code called "ledstrip.h". Which basically is an 1 dimensional array.
This is something for my study.
I am trying to send 12 bytes through a 'ledstrip'
code:
#define SPI_SS_bm PIN4_bm
#define SPI_MOSI_bm PIN5_bm
#define SPI_MISO_bm PIN6_bm
#define SPI_SCK_bm PIN7_bm
#define MIN_VALUE 0.4
#define F_CPU 32000000UL
#define P 128
#define FOO 0
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include "ledstrip.h"
void spi_init(void);
uint8_t spi_transfer(uint8_t data);
const uint8_t *ptr = image;
uint8_t num[12];
int line;
int g;
int data;
int i;
void row (const uint8_t *j)
{
uint32_t row2 = 0;
for(g = 0; g < 4; g++)
{
for(int i = 0; i < 8; i++)
{
row2 = (row2 << 3) | pgm_read_byte(j);
j++;
}
num[3*g] = (uint8_t) (row2 >> 16); //put bytes in the right order
num[3*g+1] = (uint8_t) (row2 >> 8);
num[3*g+2] = (uint8_t) (row2);
}
}
void spi_initialisation(void)
{
PORTC.DIRSET = SPI_SCK_bm|SPI_MOSI_bm|SPI_SS_bm;
PORTC.DIRCLR = SPI_MISO_bm;
SPIC.CTRL = (!SPI_CLK2X_bm) | // no double clock speed
SPI_ENABLE_bm | // SPI enable
!SPI_DORD_bm | // data order, MSB first
SPI_MASTER_bm | // master
SPI_MODE_0_gc | // mode 0
SPI_PRESCALER_DIV4_gc; // Presc. 4 (#2 MHz,500kHz)
}
void spi_init(void)
{
PORTC.DIRSET = PIN7_bm|PIN5_bm|PIN4_bm; // 7: MOSI 5: SCK
PORTC.OUTCLR = PIN4_bm; // 4: latch enable
PORTD.DIRSET |= PIN3_bm|PIN1_bm; // 3: MOSI 1: SCK
USARTC1.BAUDCTRLA = 0; // baud rate FCPU/2
USARTC1.BAUDCTRLB = 0; //
USARTC1.CTRLC = USART_CMODE_MSPI_gc; // SPI mode
USARTC1.CTRLA = 0; // no interrupts
USARTC1.CTRLB = USART_TXEN_bm; // enable transmit
USARTD0.BAUDCTRLA = 0; // baud rate FCPU/2
USARTD0.BAUDCTRLB = 0; //
USARTD0.CTRLC = USART_CMODE_MSPI_gc; // SPI mode
USARTD0.CTRLA = 0; // no interrupts
USARTD0.CTRLB = USART_TXEN_bm; // enable transmit
}
void init_timer_phi(void)
{
TCE0.CTRLA = TC_CLKSEL_DIV8_gc; // prescaling P
TCE0.CTRLB = TC_WGMODE_NORMAL_gc; // normal mode
TCE0.INTCTRLA = TC_OVFINTLVL_LO_gc;
TCE0.PER = 1440; // t = PER*FCPU/P =
// FCPU*P/32M = 1 us
}
ISR (TCE0_OVF_vect)
{
ptr = ptr +32;
if(ptr >= image + 32 * 360)
{
ptr = image;
} // send bytes to ledstrip
}
void init_inputcapture(void)
{
PORTC.PIN2CTRL = PORT_ISC_FALLING_gc;
PORTC.DIRCLR = PIN2_bm; // Pin 2 is input
EVSYS.CH0MUX = EVSYS_CHMUX_PORTC_PIN2_gc; // Select PC2 as input
// to event channel 0
TCC0.CTRLD = TC_EVACT_CAPT_gc | // Event capture
TC_EVSEL_CH0_gc; // for Channel 0
TCC0.CTRLB = TC0_CCAEN_bm; // Enable Inp. Capt. Ch. A
TCC0.CTRLA = TC_CLKSEL_DIV256_gc; // Start timer
TCC0.INTCTRLB = TC_CCAINTLVL_LO_gc; // Set Interr. level Ch. A
TCC0.PER = 0xFFFF;
}
ISR(TCC0_CCA_vect)
{
uint16_t v;
v = TCC0.CCA;
if (v > MIN_VALUE)
{ // skip if measured value is too small
line = 0; // reset image
TCE0.PER = (v * 360/(F_CPU / P)); // calculate periode
TCC0.CTRLFSET = TC_CMD_RESTART_gc; // restart input capture
}
}
void spi_write_byte(uint8_t data)
{
PORTC.OUTCLR = SPI_SS_bm;
spi_transfer(data);
PORTC.OUTSET = SPI_SS_bm;
}
uint8_t spi_read_byte(void)
{
uint8_t data;
PORTC.OUTCLR = SPI_SS_bm;
data = spi_transfer (FOO);
PORTC.OUTSET = SPI_SS_bm;
return data;
}
int main(void)
{
uint8_t i = 0;
spi_init();
PORTC.DIRSET = PIN0_bm;
PMIC.CTRL |= PMIC_LOLVLEN_bm;
sei();
PORTC.DIRSET = PIN4_bm | PIN5_bm | PIN6_bm | PIN7_bm;
while(1)
{
SPIC.DATA = i; // send i
while( ! (SPIC.STATUS & (SPI_IF_bm)) ); // wait until send
PORTC.OUTSET = PIN0_bm; // store
PORTC.OUTCLR = PIN0_bm;
_delay_ms(100);
i++;
}
}
Okay, so I got this code with no errors and warnings.
But when I run the program on my microcontroller ATXMega128A4U, I don't get the intended output.
There is a possibility that I didn't connect the pins of my 'ledstrip' in the right way with the pins of the microcontroller.
But if we consider that I did it like I intended to, the problem should be in the code.
The intended signal is 12 bytes long and with that I can turn RGB LED's on or off.
The RGB LED's are put together in a so called 'ledstrip'
Now what I'm getting is that some of the RGB LED's turn on and are Red Green or Blue.
What i should be getting is something like a chasing RGB LED row.
So you would see the LED's turn on or off at a certain frequency.
I am trying to get a pic16 controller to run an initialization function that displays some text on an LCD only once and then goes on to display other things
The LCD output is working fine the problem is that the initialization function keeps executing. What am I doing wrong ?
/*
* File: main.c
*
* Created on Sep 1, 2013, 12:09 PM
*/
#include <pic.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "delay.h"
__CONFIG(WDTE_ON & PWRTE_ON & MCLRE_ON & BOREN_ON & FOSC_INTRCIO );
static int exec_counter = 0;
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) // bit mask macros
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define flip_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
#define test_bit(ADDRESS,BIT) (ADDRESS & (1<<BIT))
#define E RC4 // Define the LCD Control Pins
#define RS RC5
int i; // Use Global Variables for Debug
LCDWrite(int LCDData, int RSValue)
{
PORTC = (LCDData >> 4) & 0x0F; // Get High 4 Bits for Output
RS = RSValue;
E = 1; E = 0; // Toggle the High 4 Bits Out
PORTC = LCDData & 0x0F; // Get Low 4 Bits for Output
RS = RSValue;
E = 1; E = 0; // Toggle the Low 4 Bits Out
if ((0 == (LCDData & 0xFC)) && (0 == RSValue))
DelayMs(5);
else
DelayUs(200);
} //
void writeLines(char top[],char bottom[]){
for (i = 0; top[i] != 0; i++) // Write Line 1
LCDWrite(top[i], 1);
LCDWrite(0b11000000, 0); // Move Cursor to the Second Line
for (i = 0; bottom[i] != 0; i++)// Write Line 2
LCDWrite(bottom[i], 1);
}
int countelems(char arr[]){
for (i = 0; arr[i] != 0; i++){}
return i;
}
void pad_number(char number[],char numberout[],char unit[]){
int size_n = countelems(number); // get length of number array by reference
int size_u = countelems(unit); // get length of unit array by reference
int size = size_u + size_n + 1; // calculate total size of text with 1 space between number and unit
int L_space = floor((16-size)/2)-1; // calculate space required on left side of display to center text
for (i = 0; i <= 15; i++)
numberout[i] = 0b10100000; // fill output char array with spaces
for (i = 0; i <= (size_n); i++){
numberout[i+(L_space+1)] = number[i]; // fill output char array with number
}
numberout[L_space+size_n+1] = 0b10100000; // put space in output char array between number and unit
for (i = 0; i <= size_u; i++){
numberout[i+(L_space+size_n+2)] = unit[i]; // fill output char array with unit
}
}
void pad_text(char text[],char textout[]){
int size = countelems(text); // get length of char array by reference
int L_space = floor((16-size)/2); // calculate space required on left side of display to center text
for (i = 0; i <= 15; i++)
textout[i] = 0b10100000; // fill output char array with spaces
for (i = 0; i <= 15; i++){
if( i >= L_space && i <= (L_space+size)){
textout[i] = text[i-L_space]; // fill middle of output char array with text
}
}
}
void getAnalog(int channel,char parameter[], char unit[]){
char output_parameter[16];
char output_number[16];
char number[16];
ADCON0 = channel << 2; // select channel
//set_bit(ADCON0,7); // set ADFM flag so LSB is bit 0 of ADRESL
set_bit(ADCON0,0); // switch ADC on = set ADON flag 0b00000001
sampleTime(); // wait required aquisition time
set_bit(ADCON0,1); // start conversion = set GO/DONE bit
while(test_bit(ADCON0,1)){/* wait for ADC to complete conversion */;}
int ADCresult = (ADRESL+ADRESH)/10; // get result from ADC
itoa(number,ADCresult,10); // convert ADC result to charstring
LCDWrite(0b00000001, 0); // Clear LCD
pad_text(parameter,output_parameter);
pad_number(number,output_number,unit);
writeLines(output_parameter, output_number);
}
void init(){
DelayMs(20); // Wait for LCD to Power Up
PORTC = 3; // Start Initialization Process
E = 1; E = 0; // Send Reset Command
DelayMs(5);
E = 1; E = 0; // Repeat Reset Command
DelayUs(200);
E = 1; E = 0; // Repeat Reset Command Third Time
DelayUs(200);
PORTC = 2; // Initialize LCD 4 Bit Mode
E = 1; E = 0;
DelayUs(200);
LCDWrite(0b00101000, 0); // LCD is 4 Bit I/F, 2 Line
LCDWrite(0b00000001, 0); // Clear LCD
LCDWrite(0b00000110, 0); // Move Cursor After Each Character
LCDWrite(0b00001110, 0); // Turn On LCD and Enable Cursor
// "0123456789012345"
writeLines( " INITIALIZE ",
" TEXT ");
}
void main(void) {
OPTION_REG |= 0x7; // set prescaler to 1:128 or 2.3 Seconds
OPTION_REG |= 0x8; // assign prescaler to WDT
TRISA = 0b00000101; // configure PORTA set RA0 and RA2 to analog input;
ANSEL = 0b00000101; // disable input buffers if I/O pins RA0 and RA2
TRISC = 0; // configure PORTC as output
ADCON1 = 0; // select FOSC2
if (exec_counter == 0){
exec_counter++;
init();
DelayS(4);
}
PORTC = 0;
while (1) {
getAnalog(0,"VELOCITY","KM/H");
DelayS(4);
getAnalog(2,"ACCELERATION","M/S^2");
DelayS(4);
}
return;
}
/*
* File: delay.c
*
* Created on Sep 3, 2013, 12:09 PM
*/
#include "delay.h"
#include <pic.h>
#define _XTAL_FREQ 4000000
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char i;
do {
i = 4;
do {
DelayUs(250);
} while(--i);
} while(--cnt);
#endif
}
void DelayS(unsigned int count){
for (int i=0; i<=count;i++){
NOP();
CLRWDT();
DelayMs(1000);
}
}
void sampleTime(){
// TC = – 10pF ( 1k Ω + 7k Ω + 1k Ω ) ln(0.0004885)
// = 0.686 μS
// TACQ = 5μS + 0.686μS + [ ( 50°C- 25°C ) ( 0.05μ S /°C ) ]
// = 6.936 μS /
// 1 instruction cycle = 4μS # 1 mHz
// 1 instruction cycle = 1μS # 4 mHz
// 1 instruction cycle = 500nS # 8 mHz
// 1 instruction cycle = 200nS # 20 mHz
// TACQ # 1 mHz is 6.936 μS / 4 μS or ~ 2 instruction cycles
// TACQ # 4 mHz is 6.936 μS / 1 μS or ~ 7 instruction cycles
// TACQ # 8 mHz is 6.936 μS / 0.5 μS or ~ 14 instruction cycles
// TACQ # 20 mHz is 6.936 μS / 0.2 μS or ~ 35 instruction cycles
DelayUs(8);
}
The char number[] = ""; array is very small, yet you use it in itoa(), thus overwriting random memory.