When selecting the "Build Main Project" and attempting to compile my project, the compiler keeps bringing up these error messages:
Source.c:64:8: error: 'RB6' undeclared (first use in this function)
I believe it has something to do with my #define lines of code, but I'm not certain:
// Include Commands
#include "xc.h"
#include "lcd.h"
#include <stdio.h>
#include <stdlib.h>
#include "pragma.h"
#include <stdbool.h>
// Define Commands
#define LCD_RS RB7
#define LCD_D0 RB15
#define LCD_D1 RB14
#define LCD_D2 RB13
#define ULTRAECHO RA4
#define ULTRATRIG RB5
#define PIR RB6
#define PIRII RB7
#define MOTOR RB4
#define MOTORII RB12
#define XTAL_FREQ 8000000
void setup() {
// A-Type Registers
TRISA = 0;
// 0 - 5
PORTA = 0;
// B-Type Registers
TRISB = 0;
// 0 - 15
PORTB = 0;
LCD_Cmd(LCD_CLEAR);
__delay_ms(50);
LCD_Begin();
}
void loop() {
int value;
value = 0;
__delay_ms(300);
PORTBbits.RB6 = 1;
PORTBbits.RB7 = 1;
if (PIR == 1 || PIRII == 1) { // Checks both PIR Sensors
PORTBbits.RB8 = 1; // Activates LCD Screen
PORTBbits.RB15 = 1;
PORTBbits.RB14 = 1;
PORTBbits.RB13 = 1;
PORTAbits.RA4 = 1; // Activates ULTRASONIC
PORTBbits.RB5 = 1;
LCD_Cmd(LCD_CLEAR);
(value = value + 1);
}
else {
PORTBbits.RB8 = 0; // No Life Detected
PORTBbits.RB15 = 0;
PORTBbits.RB14 = 0;
PORTBbits.RB13 = 0;
(value = value);
}
{
LCD_Goto(1, 1);
LCD_Print(value);
goto __delay_ms(300);
}
{
if (PORTAbits.RA4 = 1 || PORTBbits.RB5 = 1) {
__bit wait_sensor(); // Activates Timer
uint16_t i = 0;
TMR1 = 0; // Resets Timer
TMR1 = 1;
while (!ULTRAECHO && (i < 1000)) {
i = (TMR1 << 8) | TMR1;
if (i >= 1000)
return 0;
else {
return 1;
}
}
}
__bit get_distance(uint16_t *ticks);
{
uint16_t *ticks = 0;
TMR1 = 0;
while (ULTRAECHO && ('uint16_t *ticks' < 23200))
uint16_t *ticks = (TMR1 << 8) | TMR1; // Read Timer Value
TMR1 = 0;
if (uint16_t *ticks >= 23200)
return 1;
else {
return 0;
}
}
{
OSCCON = 0x70; // Sets Timer and Oscillator Value
T1CON = 0x10;
TMR1 = 0;
__delay_ms(500);
ULTRATRIG = 0; // Toggle Pin to LOW
__delay_us(2);
ULTRATRIG = 1; // Generate 10us Pulse
__delay_us(10);
ULTRATRIG = 0;
if (ULTRAECHO = 1) // Read Pulse from ULTRAECHO
uint16_t distance;
if (get_distance()) { // Distance greater than 400cm
LCD_Goto(2, 1);
LCD_Print(" No Proximity ");
MOTORII = 0;
MOTOR = 0;
}
else {
uint16_t distance = uint16_t distance / 58; // Calculates Distance
LCD_Goto(2, 1);
LCD_Print(distance, " cm ");
MOTORII = 1;
MOTOR = 1;
}
uint16_t distance = uint16_t distance / 58;
if (uint16_t distance <= 20)
MOTORII = 0;
MOTOR = 0;
__delay_ms(500);
goto void setup();
}
}
}
Perhaps the placement of my "define" commands are incorrect? Or is there some sort of line of code I'm forgetting? I feel like I'm overthinking this.
Yes, there are issues with your #define directives. They are not defined as they ought to be.
In this block of code:
// Define Commands
#define LCD_RS RB7
#define LCD_D0 RB15
#define LCD_D1 RB14
#define LCD_D2 RB13
#define ULTRAECHO RA4
#define ULTRATRIG RB5
#define PIR RB6
#define PIRII RB7
#define MOTOR RB4
#define MOTORII RB12
Define those macros as:
#define LCD_RS PORTBbits.RB7 //Check if it is RB7 or RB8, as somwhere it is RB8
#define LCD_D0 PORTBbits.RB15
#define LCD_D1 PORTBbits.RB14
#define LCD_D2 PORTBbits.RB13
#define ULTRAECHO PORTAbits.RA4
#define ULTRATRIG PORTBbits.RB5
#define PIR PORTBbits.RB6
#define PIRII PORTBbits.RB7
#define MOTOR PORTBbits.RB4
#define MOTORII PORTBbits.RB12
And use them for example as:
...
PIR = 1;
PIRII = 1;
if (PIR == 1 || PIRII == 1) { // Checks both PIR Sensors
LCD_RS = 1; // Activates LCD Screen
LCD_D0 = 1;
LCD_D1 = 1;
LCD_D2 = 1;
...
Apart from those issues, I think your Input and Output configuring registers TRISA and TRISB are not properly configured.
// A-Type Registers
TRISA = 0;
// 0 - 5
PORTA = 0;
// B-Type Registers
TRISB = 0;
// 0 - 15
PORTB = 0;
In the controller header there is a define like:
#define _RB7 PORTBbits.RB7
so you could also use something like:
#define LCD_RS _RB7
Related
#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(;;)
{
}
}
I newbie in PIC mcu. I use pic12f675 MPLAB and XC8 for make an LED multiple blink pattern.
and I have problem with push button (after review it call Bounce and Debounce).
Sometime when I press button it will in sequence ex. 1->2->3->4->5 but sometime it will jump ex. 1->3->4->6 etc.
Please advice me How to debounce in pic mcu or another way to solve my problem.
Thank you. everyone.
(PS.I connect push button with 10K resistor)
my code at below
#include <xc.h>
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
#define _XTAL_FREQ 4000000
int cnt = 0;
int k = 0;
void __interrupt() MyISR(void){
if(INTCONbits.INTF) //If External Edge INT Interrupt
{
cnt++;
INTCONbits.GIE = 0;
INTCONbits.INTF = 0; // Clear the interrupt
INTCONbits.GPIF = 0;
if( cnt > 6 ){
cnt = 1;
}
}
INTCONbits.GIE = 1;
}
void main(void) {
ANSEL = 0;
CMCON = 0b00000111; //turns comparators off
TRISIO = 0b00000100;
GPIO = 0;
TRISIO2 = 1; // Make GP2 pin as input
INTCONbits.GIE = 1;
INTCONbits.INTE = 1;
INTCONbits.GPIF = 1;
INTCONbits.INTF = 0;
OPTION_REG = 0b01000000;
while(1){
if( cnt == 1 ){
GP0 = 1;
GP5 = 1;
}else if( cnt == 2 ){
for(k=0;k<30;k++){
GP5 = 1;
GP0 = 1;
}
k=0;
while(k<3){
GP5 = ~GP5;
__delay_ms(70);
GP0 = ~GP0;
__delay_ms(70);
k++;
}
}else if( cnt == 3 ){
for(k=0;k<5;k++){
GP5 = 1;
GP0 = 1;
__delay_ms(70);
GP5 = 0;
GP0 = 0;
__delay_ms(70);
}
GP5 = 0;
GP0 = 0;
__delay_ms(1200);
}else if( cnt == 4 ){
for(k=0;k<3;k++){
GP0 = 1;
__delay_ms(50);
GP0 = 0;
__delay_ms(50);
}
for(k=0;k<3;k++){
GP5 = 1;
__delay_ms(50);
GP5 = 0;
__delay_ms(50);
}
}else if( cnt == 5 ){
GP0 = 1;
GP5 = 1;
for(k=0;k<3;k++){
GP5 = 1;
__delay_ms(50);
GP5 = 0;
__delay_ms(50);
}
GP0 = 1;
GP5 = 1;
for(k=0;k<3;k++){
GP0 = 1;
__delay_ms(50);
GP0 = 0;
__delay_ms(50);
}
}else if( cnt == 6 ){
GP0 = 1;
GP5 = 1;
__delay_ms(20);
GP0 = 0;
GP5 = 0;
__delay_ms(3000);
}
}
return;
}
I rewrite your code and tested it in MPLAB simulation. It works as expected. It changes modes in ascending order, then runs in the selected mode until the change button pressed again, then it changes to the next mode. You can add more working modes if you want or you can modify the way the how GPIOs blinking. There is no __delay_ms(), that's why the delays run without consuming the CPU. Please test it in a real circuit and give me a feedback.
/*
* File: main.c
* Author: kozmotronik
*
*/
#define _XTAL_FREQ 4000000
#include <xc.h>
#include <stdint.h>
#include <stdbool.h>
#pragma config FOSC=INTRCIO,WDTE=OFF,MCLRE=OFF,BOREN=OFF
// Work mode definitions
#define MODE_IDLE 0
#define MODE_OFF 1
#define MODE_ON 2
#define MODE_SLOW 3
#define MODE_FAST 4
#define MODE_CANCEL 5
#define LAST_MODE MODE_FAST
// Button states
#define BUTTON_IDLE 0
#define BUTTON_PRESS_DETECTED 1
#define BUTTON_DEBOUNCING 2
#define BUTTON_PRESS_CONFIRMED 3
#define SYSTEM_CLOCK_MS 1
#define SYSTEM_CLOCK_uS (SYSTEM_CLOCK_MS * 1000)
#define _XTAL_FREQ_MHZ (_XTAL_FREQ / 1000000) // Oscillator freq in MHz
#define TMR0_RELOAD_VALUE 256 - ( (SYSTEM_CLOCK_uS * _XTAL_FREQ_MHZ) / (8 * 4) ) // Result must be 131
#define MS_TO_TICKS(msTime) (msTime / SYSTEM_CLOCK_MS)
typedef struct{
unsigned int start;
unsigned int ticks;
} time_t;
char mode = MODE_IDLE;
char lastMode = MODE_OFF;
char buttonState = BUTTON_IDLE;
char k = 0;
unsigned int systemTick = 0; // Time value count by Timer0
void __interrupt() MyISR(void){
if(INTCONbits.INTF) //If External Edge INT Interrupt
{
INTCONbits.INTF = 0; // Clear the interrupt
buttonState = BUTTON_PRESS_DETECTED; // Signal the detected press
}
// Check for 1 ms periodic interrupt for system clock
else if(INTCONbits.T0IF){
INTCONbits.T0IF = 0; // clear flag
TMR0 = TMR0_RELOAD_VALUE; // Reload the calculated value for 1 ms
systemTick++;
}
}
// Setup Timer0 for 1ms interrupt
void setupTimer0(){
#define PRESCALER_VALUE 2
#define PRESCALER_MASK ~7
OPTION_REG &= PRESCALER_MASK; // Clear prescaler bits
OPTION_REG |= PRESCALER_VALUE; // Set prescaler value for 1:8
OPTION_REGbits.PSA = 0; // Assign prescaler to Tim0
OPTION_REGbits.T0CS = 0; // Set internal oscillator as clock source
TMR0 = TMR0_RELOAD_VALUE;
INTCONbits.T0IF = 0;
INTCONbits.T0IE = 1; // Enable Timer0 interrupt
}
// Get count atomically
unsigned int getTickCount(){
unsigned int count;
di(); // disable interrupts
count = systemTick;
ei(); // enable interrupts again
return count;
}
void performMode(){
static time_t modeDelay;
static char slowModeState = 1;
static char fastModeState = 1;
switch(mode){
case MODE_OFF:
// Always must save the current mode before put it into the IDLE
lastMode = mode; // We have to save the last mode first then put it into the IDLE state
mode = MODE_IDLE; // The rollover bug caused by here since we haven't save the last mode before put it into the IDLE state
GP0 = 0; GP5 = 0;
break;
case MODE_ON:
GP0 = 1; GP5 = 1;
break;
case MODE_SLOW:
if(slowModeState == 1){
GP0 = 1; GP5 = 1;
modeDelay.ticks = MS_TO_TICKS(100);
modeDelay.start = getTickCount();
slowModeState = 2; // Proceed the next step
}
else if(slowModeState == 2){
if( !((getTickCount() - modeDelay.start) >= modeDelay.ticks) ){
// Delay not expired yet
return;
}
GP0 = ~GP0; GP5 = ~GP5; // Toggle
// Reload the start time
modeDelay.start = getTickCount();
}
break;
case MODE_FAST:
if(fastModeState == 1){
GP0 = 1; GP5 = 1;
modeDelay.ticks = MS_TO_TICKS(50);
modeDelay.start = getTickCount();
fastModeState = 2; // Proceed the next step
}
else if(fastModeState == 2){
if( !((getTickCount() - modeDelay.start) >= modeDelay.ticks) ){
// Delay not expired yet
return;
}
// Delay time expired, proceed toggle
GP0 = ~GP0; GP5 = ~GP5; // Toggle
// Reload the start time
modeDelay.start = getTickCount();
}
break;
case MODE_CANCEL:
// Cancel the current running mode, reset everything
modeDelay.start = 0;
modeDelay.ticks = 0;
slowModeState = 1;
fastModeState = 1;
// Also reset the outputs
GP0 = 0; GP5 = 0;
break;
default:
mode = MODE_IDLE;
}
}
void checkButton(){
#define DEBOUNCE_DELAY_MS 100u // Debounce delay is 100 ms
static time_t debounceTimer;
switch(buttonState){
case BUTTON_IDLE:
break;
case BUTTON_PRESS_DETECTED:
debounceTimer.ticks = MS_TO_TICKS(DEBOUNCE_DELAY_MS);
debounceTimer.start = getTickCount();
buttonState = BUTTON_DEBOUNCING;
break;
case BUTTON_DEBOUNCING:
if( !((getTickCount() - debounceTimer.start) >= debounceTimer.ticks) ){
// Debounce time has not expired yet
return;
}
// Debounce time has expired so check the button last time to confirm if it is still pressed
if(GPIObits.GP2 != 1){
// Not stable yet, debounce again
buttonState = BUTTON_PRESS_DETECTED;
}
// Button press is stable, confirm it
buttonState = BUTTON_PRESS_CONFIRMED;
break;
case BUTTON_PRESS_CONFIRMED:
buttonState = BUTTON_IDLE; // Change state so that it can process a new button press
if(mode != MODE_IDLE && mode != MODE_OFF){
// Cancel the running mode first
lastMode = mode; // save the last mode
mode = MODE_CANCEL; // purge the current one
performMode();
}
mode = lastMode + 1; // Switch to next mode
if(mode > LAST_MODE){
// Rewind mode to the beginning which is MODE_OFF
mode = MODE_OFF;
}
break;
default:
buttonState = BUTTON_IDLE;
}
}
void main(void) {
ANSEL = 0;
CMCON = 0b00000111; //turns comparators off
TRISIO = 0b00000100;
GPIO = 0;
TRISIO2 = 1; // Make GP2 pin as input
INTCONbits.INTF = 0;
INTCONbits.INTE = 1;
INTCONbits.GIE = 1;
OPTION_REG = 0b01000000; // Rising edge interrupt
setupTimer0();
// Super loop
while(1){
// Task 1: Button check
if(buttonState != BUTTON_IDLE){
checkButton();
}
// Task 2: Mode check
else if(mode != MODE_IDLE){
performMode();
}
}
return;
}
I am using the debug function to check the TMR0IF flag but it doesn't occur. It is stuck at while(PIR0bits.TMR0IF ==0). Please advise.
#define _XTAL_FREQ 64000000
#define ACM_STEP_TRIS TRISAbits.TRISA4
#define ACM_STEP LATAbits.LATA4
#define ACM_ENABLE_TRIS TRISAbits.TRISA5
#define ACM_nENABLE LATAbits.LATA5
ACM_STEP_TRIS =0;
void main(void)
{
T0CON0bits.T0OUT = 0;
T0CON0bits.T016BIT = 1; // TMR0 is a 16-bit timer
T0CON0bits.T0OUTPS = 0; // No prescaler
T0CON1bits.T0CS =0b010; //Clock source is Fosc/4
T0CON1bits.T0ASYNC =0; //Input to TMR0 counter is synchronized to Fosc/4
T0CON1bits.T0CKPS =0; //Prescaler 1:1
while (1){
ACM_nENABLE =0; // Turn on stepper motor
__delay_ms(2);
ACM_STEP ^=1;
TMR0H = 0xFD;
TMR0L = 0xE8; // Load TMR0L
T0CON0bits.T0EN = 1; //Timer Module is enabled
while(PIR0bits.TMR0IF ==0);
T0CON0bits.T0EN = 0; //Turn off Timer
PIR0bits.TMR0IF = 0; // Clear TF0 flag
}
return;
}
Please check out this answer: http://www.edaboard.com/showthread.php?t=197899
They checks another register (INTCONbits and not PIR0bits) and everything works ok.
I am interfacing LM35 with Atmega8. To display digits I use 7 segment LED anode display that I connect to AVR both ends (it handles it without transistors so why not). Strange thing happens:
res value after assigning it from adc is 237 (23.7 degrees). I want to print on my display the first digit (2).
If I leave last line in the while commented out, the display first shows digit 2 correctly but after the first delay it shows 1 instead of 2. Otherwise I get correctly digit 2. Why is this happening?
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#define DELAY_IN_MS 500 /* 0.5 sec */
int numbers[] = {
0b01000000,
0b01110011,
0b00100100,
0b00100001,
0b00010011,
0b00001001,
0b00001000,
0b01100011,
0b00000000,
0b00000001,
0b11111111 // off
};
uint8_t digits[3];
void initADC()
{
ADMUX=(1<<REFS1)|(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while(!(ADCSRA & (1<<ADIF)));
//Clear ADIF by writing one to it
ADCSRA|=(1<<ADIF);
return(ADC);
}
int main()
{
DDRD = 0xFF;
PORTD = 0xFF;
DDRB = 0b00000001;
PORTB = 1;
initADC();
uint16_t adc_value;
uint16_t res;
while(1)
{
adc_value = 0;
for (int i = 0; i < 250; i++)
{
adc_value += ReadADC(0);
}
adc_value=(adc_value/25)/4;
res = adc_value;
for(int j = 2; j >= 0; j--) {
digits[j] = res%10;
res /= 10;
}
uint8_t dig = digits[0];
PORTD = numbers[dig];
_delay_ms(DELAY_IN_MS);
// if following is uncommented there blinks digit two correctly
// if commented there is unblinking digit 1
PORTD = numbers[10]; // display off
}
return 0;
}
The problem was induction.
My circuit had many wires in non-soldering-field. When the display was on, there was a lot of induction going on changing resulting voltage on ADC input/LM35 output.
There is more than one solution.
1) Software: I moved ADC conversion into the interruption function. It turns of the displays, converts value from lm35 and displays digit on proper display. It happens so fast that the eye cant perceive it.
I prefer this one for now, because it makes my circuit simpler.
2) Hardware: adding L/C or R/C filter to adc pin should resolve the issue.
Full code for 1)
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define DELAY_IN_MS 5000 /* ms */
#define NUM_OF_MEASUREMENTS 100
#define NUM_DISPLAYS 3
int numbers[] = {
0b10000001,
0b10011111,
0b10100100,
0b10010100,
0b10011010,
0b11010000,
0b11000000,
0b10011101,
0b10000000,
0b10010000,
0b11111111 // off
};
int display = 0;
uint8_t digits[NUM_DISPLAYS];
volatile uint16_t adc_values[NUM_OF_MEASUREMENTS];
int adc_read_cycle_index = 0;
uint32_t res;
void initADC()
{
ADMUX=(1<<REFS1)|(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2);
}
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while (ADCSRA & (1<<ADSC));
return(ADC);
}
void readDegrees()
{
adc_values[adc_read_cycle_index] = (ReadADC(0)*10)/4;
if(adc_read_cycle_index + 1 == NUM_OF_MEASUREMENTS) {
adc_read_cycle_index = 0;
} else {
adc_read_cycle_index++;
}
}
void fetchTemperatureDigits() {
res = 0;
for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
res += adc_values[i];
}
res /= NUM_OF_MEASUREMENTS;
for(int j = 2; j >= 0; j--) {
digits[j] = res%10;
res = res / 10;
}
}
void initTimer0()
{
// Prescaler = FCPU/64
TCCR0|=(1<<CS01);//|(1<<CS00);
//Enable Overflow Interrupt Enable
TIMSK|=(1<<TOIE0);
//Initialize Counter
TCNT0=0;
}
ISR(TIMER0_OVF_vect)
{
// turn off displays
PORTD = numbers[10];
// read ADC and convert to degrees
readDegrees();
// turn on proper anode
PORTB &= 0b11111000;
PORTB |= (1<<display);
// show digit
PORTD = numbers[digits[display]];
// show decimal point for second display (21.5 - second display shows "1.")
if(display == 1) {
PORTD &= 0b01111111;
}
// next display for next interruption
display++;
if(display == NUM_DISPLAYS) {
display = 0;
}
}
int main()
{
initADC();
for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
readDegrees();
}
DDRD = 0xFF;
PORTD = 0;
DDRB |= 0b00000111;
PORTB |= 1;
initTimer0();
sei();
while(1) {
fetchTemperatureDigits();
_delay_ms(DELAY_IN_MS);
}
return 0;
}
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.