• AVR Freaks

Newbie: controlling duty cycle of PWM set up with MCC

Page: < 12345.. > >> Showing page 5 of 14
Author
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 14:37:48 (permalink)
0
There are problems in your command parser. I'll try to fix it:
void Programming_Interrupt(void)
{
char s[8]="";
unsigned char x=1;
char input_char = 0;
 
Send_Programming_String;
input_char = EUSART_Read();  // You may need to implement a timeout so you don't get stuck here
switch(input_char) {
  case 'B': input_char=EUSART_Read();
    while( input_char >= '0' && input_char <= '9' && x<8 ) {
      strcat(s, input_char);
      input_char=EUSART_Read();
      x++;
      }
    NTC_Beta = atoi(s);
    break;
 
  case 'S': input_char=EUSART_Read();
    while( input_char >= '0' && input_char <= '9' && x<8 ) {
      strcat(s, input_char);
      input_char=EUSART_Read();
      x++;
     }
    Over_Temp = atoi(s);
    break;
 
  default:  printf("Input Error");
  } //end switch
Send_Programming_String;
}
//End programming interrupt and return to normal operation
}

You may need to add code to check for an X character to terminate programming mode, but I think the above will essentially do that if an unidentified command character or a non-numeric character is entered when expected. You may also want to check the result of the atoi() function for proper range before assigning it to the selected variable.
 
[edit] corrected errors and cleaned up
 
post edited by PStechPaul - 2018/05/22 15:17:22

 
#81
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 15:28:59 (permalink)
+1 (1)
If you're comparing a variable with a series of constants, use a switch() statement.
e.g.
Keyboard_Input=EUSART_Read(); //Monitor for keyboard instructions
switch(Keyboard_Input)
{
  case 'T':
    Send_Temps_DC(Temp_NTC1, Temp_NTC2, Temp_NTC3, Temp_NTC4, Fan1_DC, Fan2_DC);
    break;
  case 'P':
    Program_Constants();
    break;
}

 
post edited by qɥb - 2018/05/22 15:30:05

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#82
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 18:38:21 (permalink)
0
Hi.  I'm trying to understand the differences. (I think I am ok without a timeout. Operation should not start again until the user finishes programming constants and types 'X'.)
 
Your code creates an empty 8 character array.  Mine does the same but pads it with * so it can be used as a check. (If not * then...)  Well I guess it is 9 characters as I understand the compiler adds \0 at the end. 
 
I made a minor mistake in that x could just be an integer as it just halts reading after 8 characters.  It also needs to be reset to 0 and the end of the read. 
 
You take the first character and then make a decision.  I read all 8 characters (I looked here how they changed an individual character in a string) and then decide what to do by looking at the first character in the array s[0]. 
 
You use strcat to tack each new character onto the previous ones. I just set the relevant spot in the array to the character entered. (See below)
 
Surely this is basically the same thing or just another way to skin the cat.
 
The key difference I see is that I accept up to 8 characters and then need to grab a chunk of them, s[3] and s[3] for temperatures and s[2], s[3], s[4] and s[5] for NTC beta and create a string from just those.  We both try to atoi that to the constant in question. 
 
So basically it seems I can't grab a couple of characters from my array and strcat them together. But if I simply use the same strategy I used to capture the array s:
 

char buffer1[4];
char buffer2[2];
switch (s[0])
{
case 'B':
buffer1[0] = s[2];
buffer1[1] = s[3];
buffer1[2] = s[4];
buffer1[3] = s[5];
NTC_Beta = atoi(buffer1);
break;

 
my compiler warning for the buffer1[x] lines are gone. Nonetheless, as soon as I type atoi in front of buffer1 I get a message "unable to resolve identifier atoi", even before I run the compiler. If I run the compiler anyway I get "function declared implicit integer". 
 
I can't even have the following without an error message re atoi. 
 

char t[2]="12";
Over_Temp = atoi(t);

 
If I set up char s[8]=""; as you have and use 
 

input_char=EUSART_Read();
strcat(s, input_char);
x++;

 
to capture characters to s as you did I get the same warnings as before:
 
main.c:268: warning: (357) illegal conversion of integer to pointer 
 
against the line with strcat and

main.c:286: warning: (361) function declared implicit int
 
So either way the build fails. 
#83
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 18:39:27 (permalink)
0
qɥb
If you're comparing a variable with a series of constants, use a switch() statement.



ok
#84
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 18:50:08 (permalink)
0
Read the documentation for atoi() in the XC8 User Guide.
The first thing you will see is that it needs you to include stdlib.h if you are going to use atoi().
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#85
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 19:12:12 (permalink)
0
SGK
main.c:268: warning: (357) illegal conversion of integer to pointer 

Which source line generated this error?
If it was the strcat(), then the first parameter is not a pointer.
Show the whole function that failed and we can spot the problem, what you have is too fragmented.,
 

main.c:286: warning: (361) function declared implicit int

That's probably from the use of atoi() without stdlib.h being included,
or strcat() without string.h being included.
 
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#86
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 20:34:32 (permalink)
0
qɥb
Read the documentation for atoi() in the XC8 User Guide.
The first thing you will see is that it needs you to include stdlib.h if you are going to use atoi().
 


 
Oh <multiple expletives>!!!
 
qɥb
SGK
main.c:268: warning: (357) illegal conversion of integer to pointer 

Which source line generated this error?
If it was the strcat(), then the first parameter is not a pointer.
Show the whole function that failed and we can spot the problem, what you have is too fragmented.,
 

main.c:286: warning: (361) function declared implicit int

That's probably from the use of atoi() without stdlib.h being included,
or strcat() without string.h being included.
 
 




The whole code at that point is in post 67. I had string.h included but not stdlib.h.
 
Full current code is below. I need to go through everything again in the morning. (I'm at 98% program memory utilisation.)
 
Builds ok now. Here is the compiler output. I've marked in bold the relevant code which causes the warnings. The first is MCC-generated code. The two I didn't annotate are just because of the way I split the code string over two lines. The string of other warnings below all come from outside my code.
 
make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory '/Users/steve/MPLABXProjects/Annealer.X'
make -f nbproject/Makefile-default.mk dist/default/production/Annealer.X.production.hex
make[2]: Entering directory '/Users/steve/MPLABXProjects/Annealer.X'
"/Applications/microchip/xc8/v1.45/bin/xc8" --pass1 --chip=16F1829 -Q -G --double=24 --float=24 --opt=+asm,+asmfile,-speed,+space,-debug,-local --addrqual=ignore --mode=free -P -N255 --warn=-3 --asmlist -DXPRJ_default=default --summary=default,-psect,-class,+mem,-hex,-file --output=default,-inhx032 --runtime=default,+clear,+init,-keep,-no_startup,-osccal,-resetbits,-download,-stackcall,+clib --output=-mcof,+elf:multilocs --stack=compiled:auto:auto "--errformat=%f:%l: error: (%n) %s" "--warnformat=%f:%l: warning: (%n) %s" "--msgformat=%f:%l: advisory: (%n) %s" -obuild/default/production/main.p1 main.c
main.c:167: warning: (373) implicit signed to unsigned conversion  OvrTmpLED_Toggle();
main.c:198: warning: (356) implicit conversion of float to integer    int Round_Adj_Temp = round(Adj_Temp);
main.c:203: warning: (373) implicit signed to unsigned conversion  if (Fan_Num == 1) PWM4_LoadDutyValue(CCPR_Val);
main.c:204: warning: (373) implicit signed to unsigned conversion  else if (Fan_Num == 2) PWM3_LoadDutyValue(CCPR_Val);
main.c:222: warning: (336) string concatenation across lines   
main.c:251: warning: (336) string concatenation across lines
main.c:267: warning: (373) implicit signed to unsigned conversion  s[x] = EUSART_Read(); in Program_Constants
"/Applications/microchip/xc8/v1.45/bin/xc8" --chip=16F1829 -G -mdist/default/production/Annealer.X.production.map --double=24 --float=24 --opt=+asm,+asmfile,-speed,+space,-debug,-local --addrqual=ignore --mode=free -P -N255 --warn=-3 --asmlist -DXPRJ_default=default --summary=default,-psect,-class,+mem,-hex,-file --output=default,-inhx032 --runtime=default,+clear,+init,-keep,-no_startup,-osccal,-resetbits,-download,-stackcall,+clib --output=-mcof,+elf:multilocs --stack=compiled:auto:auto "--errformat=%f:%l: error: (%n) %s" "--warnformat=%f:%l: warning: (%n) %s" "--msgformat=%f:%l: advisory: (%n) %s" --memorysummary dist/default/production/memoryfile.xml -odist/default/production/Annealer.X.production.elf build/default/production/mcc_generated_files/adc.p1 build/default/production/mcc_generated_files/mcc.p1 build/default/production/mcc_generated_files/device_config.p1 build/default/production/mcc_generated_files/pin_manager.p1 build/default/production/main.p1 build/default/production/mcc_generated_files/pwm4.p1 build/default/production/mcc_generated_files/pwm3.p1 build/default/production/mcc_generated_files/tmr2.p1 build/default/production/mcc_generated_files/eusart.p1 build/default/production/mcc_generated_files/interrupt_manager.p1
Microchip MPLAB XC8 C Compiler (Free Mode) V1.45
Build date: Nov 15 2017
Part Support Version: 1.45
Copyright (C) 2017 Microchip Technology Inc.
License type: Node Configuration
:: warning: (1273) Omniscient Code Generation not available in Free mode
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:414: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:414: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:414: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:416: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:416: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:431: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:431: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:431: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:433: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:433: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:434: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:437: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:437: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:437: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:439: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:439: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:440: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:517: warning: (346) declaration of "exp" hides outer declaration
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:538: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:541: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:623: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1113: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1136: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1137: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1201: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1227: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1229: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1232: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1259: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1305: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1306: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1489: warning: (373) implicit signed to unsigned conversion
/Applications/microchip/xc8/v1.45/sources/common/doprnt.c:1524: warning: (373) implicit signed to unsigned conversion
mcc_generated_files/adc.c:83: warning: (520) function "_ADC_SelectChannel" is never called
mcc_generated_files/adc.c:91: warning: (520) function "_ADC_StartConversion" is never called
mcc_generated_files/adc.c:98: warning: (520) function "_ADC_IsConversionDone" is never called
mcc_generated_files/adc.c:104: warning: (520) function "_ADC_GetConversionResult" is never called
mcc_generated_files/adc.c:133: warning: (520) function "_ADC_TemperatureAcquisitionDelay" is never called
mcc_generated_files/pin_manager.c:105: warning: (520) function "_PIN_MANAGER_IOC" is never called
main.c:244: warning: (520) function "_Send_Programming_String" is never called
mcc_generated_files/tmr2.c:79: warning: (520) function "_TMR2_StartTimer" is never called
mcc_generated_files/tmr2.c:85: warning: (520) function "_TMR2_StopTimer" is never called
mcc_generated_files/tmr2.c:91: warning: (520) function "_TMR2_ReadTimer" is never called
mcc_generated_files/tmr2.c:100: warning: (520) function "_TMR2_WriteTimer" is never called
mcc_generated_files/tmr2.c:106: warning: (520) function "_TMR2_LoadPeriodRegister" is never called
mcc_generated_files/tmr2.c:111: warning: (520) function "_TMR2_HasOverflowOccured" is never called
mcc_generated_files/eusart.c:113: warning: (520) function "_EUSART_is_tx_ready" is never called
mcc_generated_files/eusart.c:118: warning: (520) function "_EUSART_is_rx_ready" is never called
mcc_generated_files/eusart.c:123: warning: (520) function "_EUSART_is_tx_done" is never called
mcc_generated_files/eusart.c:171: warning: (520) function "_getch" is never called
main.c:273: warning: (759) expression generates no code
Memory Summary:
Program space used 1F4Fh ( 8015) of 2000h words ( 97.8%)
Data space used F2h ( 242) of 3F0h bytes ( 24.0%)
EEPROM space used 6h ( 6) of 100h bytes ( 2.3%)
Data stack space used 0h ( 0) of 30Ah bytes ( 0.0%)
Configuration bits used 2h ( 2) of 2h words (100.0%)
ID Location space used 0h ( 0) of 4h bytes ( 0.0%)

You have compiled in FREE mode.
Using Omniscient Code Generation that is available in PRO mode,
you could have produced up to 60% smaller and 400% faster code.
See http://www.microchip.com/MPLABXCcompilers for more information.
make[2]: Leaving directory '/Users/steve/MPLABXProjects/Annealer.X'
make[1]: Leaving directory '/Users/steve/MPLABXProjects/Annealer.X'
BUILD SUCCESSFUL (total time: 3s)
Loading code from /Users/steve/MPLABXProjects/Annealer.X/dist/default/production/Annealer.X.production.hex...
Loading completed
 
 

/**


#include "mcc_generated_files/mcc.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
MAIN APPLICATION
*/

//DEFINE GLOBAL CONSTANTS ETC
#define NO_CASE (IRswitch_GetValue()==HIGH) //IR beam not blocked
#define CASE (IRswitch_GetValue()==LOW) //IR beam blocked
#define NTC_Balance_Resistor 4700 //Balance resistor used in NTC voltage divider
#define Max_ADC 1023.0 //10 bit DAC
#define Room_TempK 298.15 //25C in Kelvin x 100
#define Res_Room_Temp 10000 //NTC resistance at 25C from data sheet
#define Not_Over_Heating (High_Temp_Fan1 < Over_Temp || High_Temp_Fan2 < Over_Temp)
eeprom int NTC_Beta = 3435; //NTC beta from data sheet
eeprom int Over_Temp = 70; //Temperature limit for shutdown
eeprom int Duty_Cycle50_Limit = 30; //Temperature limit for 50% duty cycle operation
void main(void)
{
// initialize the device
SYSTEM_Initialize();

// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
//INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();

IRswitch_SetDigitalInput(); //Set up PIC pins and initial conditions
TimerStart_SetDigitalOutput();
OvrTmpLED_SetDigitalOutput();
TimerStart_SetLow();
OvrTmpLED_SetLow();
char Switch_Cleared = 'N';
float Temp_NTC1=25;
float Temp_NTC2=25;
float Temp_NTC3=25;
float Temp_NTC4=25;
char Keyboard_Input;
int Fan1_DC;
int Fan2_DC;

float readNTC(adc_channel_t channel); //Declare functions
int Set_Duty_Cycle(int Fan_Num, float Fan_Temp);
void Send_String(const char *x);
void Send_Welcome(void);
void Send_Programming_String(void);
void Send_Temps_DC(float Temp1, float Temp2, float Temp3, float Temp4, int DC1, int DC2);
void Program_Constants(void);

Send_Welcome(); //Send welcome to RS232 connected PC

while (1) //MAIN LOOP
{

Temp_NTC1=readNTC(NTC1); //Read temperatures
Temp_NTC2=readNTC(NTC2);
Temp_NTC3=readNTC(NTC3);
Temp_NTC4=readNTC(NTC4);
float High_Temp_Fan1=0; //Calculate max temp of NTC pairs
if (Temp_NTC1>=Temp_NTC2){
High_Temp_Fan1=Temp_NTC1;}
else
High_Temp_Fan1=Temp_NTC2;

float High_Temp_Fan2=0;
if (Temp_NTC3>=Temp_NTC4){
High_Temp_Fan2=Temp_NTC3;}
else
High_Temp_Fan2=Temp_NTC4;


Fan1_DC = Set_Duty_Cycle(1,High_Temp_Fan1); //Set duty cycle CCPR values and return duty cycles
Fan2_DC = Set_Duty_Cycle(2,High_Temp_Fan2);

Keyboard_Input=EUSART_Read(); //Monitor for keyboard instructions
switch(Keyboard_Input){
case 'T':
Send_Temps_DC(Temp_NTC1, Temp_NTC2, Temp_NTC3, Temp_NTC4, Fan1_DC, Fan2_DC);
break;
case 'P':
Program_Constants();
break;
}


if (Not_Over_Heating) //Maintain normal operation of optical switch and timer management
{
OvrTmpLED_SetLow(); //Make sure Over-Temp LED is off
if (CASE && (Switch_Cleared=='Y'))
{
for (int countDelay=0; countDelay <200; countDelay ++)__delay_ms(5); //Delay 1s for case to settle
if (CASE)
{
TimerStart_SetHigh();
for (unsigned char countDelay=0; countDelay <20; countDelay ++)__delay_ms(5);
TimerStart_SetLow();
}
}
else
{
if (NO_CASE) Switch_Cleared='Y';
}
}
else //Overheating. Blink LED. Operation can't commence until no longer overheating.
{
OvrTmpLED_Toggle();
for (int countdelay=0; countdelay<20; countdelay++)__delay_ms(10);
}

}

}

//FUNCTIONS:

//Calculate temp at an NTC in degrees Celsius
float readNTC(adc_channel_t channel)
{
int ADC_value = ADC_GetConversion(channel);
float rNTC1 = NTC_Balance_Resistor * ((Max_ADC / ADC_value)-1);
float Temp = ((NTC_Beta * (Room_TempK)) /
(NTC_Beta + ((Room_TempK) * log(rNTC1 / Res_Room_Temp)))) - 273.15;
return Temp;
}
//Set CCPR value for duty cycle and return Duty Cycle
int Set_Duty_Cycle(int Fan_Num, float Fan_Temp)
{
float Temp_Increment = ((Over_Temp -10 - Duty_Cycle50_Limit)/10);
float Adj_Temp = ((Fan_Temp - Duty_Cycle50_Limit)/Temp_Increment);
int CCPR_Val=9;
int Duty_Cycle;
int Round_Adj_Temp = round(Adj_Temp);
float Residual = (Adj_Temp-Round_Adj_Temp);
if (Residual < 0) {CCPR_Val = (Round_Adj_Temp+9);}
else {CCPR_Val = (Round_Adj_Temp + 10);}

if (Fan_Num == 1) PWM4_LoadDutyValue(CCPR_Val);
else if (Fan_Num == 2) PWM3_LoadDutyValue(CCPR_Val);

Duty_Cycle = (19 - CCPR_Val)*5;
return (Duty_Cycle);

}
//Send String
void Send_String(const char *x)
{
while (*x)
EUSART_Write(*x++);
}
//Send Welcome String
void Send_Welcome(void)
{
Send_String("GinaErick Annealer software by SGK ver 1.0 May 20, 2018\n"
"Copyright (c) protected. Non-commercial use only.\n");
Send_String("Type T to display NTC temperatures in degrees Celsius and fan duty cycles.\n");
Send_String("Type P to halt operation and enter program mode.\n");
}
//Send Temperatures and Duty Cycles
void Send_Temps_DC(float Temp1, float Temp2, float Temp3, float Temp4, int DC1, int DC2)
{
Send_String("Temperatures in degrees Celsius)\n");
char buffer [10];
printf("NTC1 %.1f\n", Temp1);
printf("NTC2 %.1f\n", Temp2);
printf("NTC3 %.1f\n", Temp3);
printf("NTC4 %.1f\n\n", Temp4);
Send_String("Duty cycles in per cent.\n");
printf("Fan 1 %d\n", DC1);
printf("Fan 2 %d\n", DC2);
Send_String("\n\n");
Send_Welcome;
}
//Send Programming String
void Send_Programming_String(void)
{
Send_String("Programming mode.\n");
printf("B for NTC beta = %d\n", NTC_Beta);
printf("S for thermal protection limit degC = %d\n", Over_Temp);
printf("F for temp limit for 50 per cent duty cycle fan operation = %d\n", Duty_Cycle50_Limit);
Send_String("X to exit and return to normal operation.\n Integer values, 2 digits for temps and 4 for beta.\n"
"Fan duty cycle is 0-step linear progression from 50 up to the 50 per cent duty cycle limit\n"
"to 100 per cent 10 degrees below the thermal protection limit.\n\n"
"To change a constant: <Constant Code> <New Value><Return> \n\n");

}
//Do programming of key constants
void Program_Constants(void)
{
Send_Programming_String;
char s[8]="";
int x=1;
char input_char = 0;
while (EUSART_Read() != 'X')
{
while (EUSART_Read() != '\r' && x<8){ //Read command
s[x] = EUSART_Read();
x++;
}
x=0;
if ((s[7] != '*') && (s[0] != 'B' || 'S' || 'F' || 'X') && (s[1] != ' ')){ //check command for errors
printf("Input Error");
}
else
{ //Process command
char buffer1[4];
char buffer2[2];
switch (s[0])
{
case 'B':
buffer1[0] = s[2];
buffer1[1] = s[3];
buffer1[2] = s[4];
buffer1[3] = s[5];
NTC_Beta = atoi (buffer1);
break;
case 'S':
if (s[4] != '*'){
printf("Input Error");
}
else {
buffer2[0] = s[2];
buffer2[1] = s[3];
Over_Temp = atoi(buffer2);
}
break;
case 'F':
if (s[4] != '*'){
printf("Input Error");
}
else {
buffer2[0] = s[2];
buffer2[1] = s[3];
Duty_Cycle50_Limit = atoi(buffer2);
}
break;
}
Send_Programming_String;
}
}
}

/**
End of File
*/

 
#87
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 20:50:24 (permalink)
0

main.c:167: warning: (373) implicit signed to unsigned conversion  OvrTmpLED_Toggle();

There is no definition for  OvrTmpLED_Toggle(); in the posted code.
 

main.c:198: warning: (356) implicit conversion of float to integer    int Round_Adj_Temp = round(Adj_Temp);

The round() function returns a float, which you are shoving into an integer variable.
 
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#88
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/22 21:02:50 (permalink)
0
qɥb
 
There is no definition for  OvrTmpLED_Toggle(); in the posted code.

 
Correct it is an MCC-generated function. I figure it is ok.
 
qɥb
 
The round() function returns a float, which you are shoving into an integer variable.
 



 
I figured that was ok as well. 
 
I have a Pickit 3 which I have used to flash hex code to a PIC before (plus a universal programming seat). I think I should be able to use that to test the EUSART interaction and program_constant menus etc.
#89
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 01:02:33 (permalink)
0
There are still major problems with this code:
void Program_Constants(void)
{
Send_Programming_String;
char s[8]="";
int x=1;
char input_char = 0;  // ******* You aren't using input_char, but you should, as explained below:
while (EUSART_Read() != 'X') // ********** You need to store the value of this character
{
while (EUSART_Read() != '\r' && x<8){ //Read command // ********* Same here
s[x] = EUSART_Read();  // ****** This will be the THIRD character received
x++;
}
x=0;
if ((s[7] != '*') && (s[0] != 'B' || 'S' || 'F' || 'X') && (s[1] != ' ')){ //check command for errors
 
// ******* s[7] would be the NINTH character received, but you probably meant to initialize s[8]="********"
 
// ******* s[0] will be the THIRD character received
 
// ******* The result of a logical OR of non-zero characters will be TRUE, probably defined as -1
printf("Input Error");
}
else
{ //Process command
char buffer1[4];  // ******* You need this to have a fifth element for \0. Or just use char buffer1[]="0000"
char buffer2[2];
switch (s[0])
{
case 'B':
buffer1[0] = s[2];  // ******* I assume you want to require a space between command and numerics ("B 1234")
buffer1[1] = s[3];
buffer1[2] = s[4];
buffer1[3] = s[5];
NTC_Beta = atoi (buffer1); // ******* buffer1 might not be null-terminated. Add buffer[4]=0
break;
case 'S':
if (s[4] != '*'){
printf("Input Error");
}
else {
buffer2[0] = s[2];
buffer2[1] = s[3];
Over_Temp = atoi(buffer2);
}
break;
case 'F':
if (s[4] != '*'){
printf("Input Error");
}
else {
buffer2[0] = s[2];
buffer2[1] = s[3];
Duty_Cycle50_Limit = atoi(buffer2);
}
break;
}
Send_Programming_String;
}
}

 
You don't need all those different size buffers and parsing. Just read the entire input character sequence into a string, terminated by a <CR> or optionally an X to abort. Then use string functions to parse the command and determine if it is valid.
 
So, once you have a string like char command[] = "B 1234" or "B1234" you can do something like:
int pos1, pos2;
char cmd_char;
char cmd_val[]="0000";
cmd_char=command[0];
pos2=0;
 
for( pos1=1; pos1<strlen(command); pos1++) {
  if( command[pos1] >= '0' and command[pos1]<='9' ) {
    cmd_val[pos2]=command[pos1];
    pos2++; }
  }
 
switch( cmd_char ) {
  case 'B': NTC_Beta = atoi (cmd_val);
    break;
 
  case 'S': Over_Temp = atoi (cmd_val);
    break;
 
  default: printf("Input Error");
  }

 
You might need to tweak that code somewhat, but it should be a good starting point.
post edited by PStechPaul - 2018/05/23 01:06:30

 
#90
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 09:25:44 (permalink)
0
You are right.  I really did mess that up. Here's a revised loop to capture multiple commands until X is typed. Hopefully this makes much better sense.  I will work on your recommendations for processing a valid command now. 
 
I did mean to initialise s - now called 'command' - with '*'. It might be better to use zeroes*. The maximum valid command length is 6 characters e.g. B 3435. Therefore I will stop recording characters after that. I will also stop recording characters to command if \r or X is typed**. The first character (command[0]) needs to be B, S or F. The second (command[1]) needs to be a space. For case B command[2-5] need to be converted to an integer. For case S or F, command[2 and 3] need to be converted.   If there is a valid command it is processed and if there isn't an error message is provided.  The process loops until X is typed.  
 
*It would be sensible to add a check that these are all characters 0-9 (hence initialising with 0 may make more sense).
** I'm still not clear what happens if someone keeps typing more than 6 characters. It seems to me the error message will be repeated until all are read, a valid command is entered or X is entered.
 

//Do programming of key constants
void Program_Constants(void)
{
Send_Programming_String;
char Command[]="******";
int count=0;
char Input_Char = '£';
while (Input_Char != 'X') { //Process multiple commands until X
while (Input_Char != 'X' && count < 6 && Input_Char != '\r'){ //Read up to 6 characters only and stop early if X or \r.
Input_Char = EUSART_Read();
Command[count] = Input_Char;
count++;
}
count=0;
if (Input_Char != 'X') { //Examine and process command. Skip if X entered.
if ((Command[0] = 'B' || 'S' || 'F') && (Command[1] = ' ')){ //Check command for input ‘‘‘‘‘errors.
//Process command and print revised values etc
Send_Programming_String;
}
else {
printf("INPUT ERROR\n\n");
Send_Programming_String;
}
}

}

}

#91
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 11:36:35 (permalink)
0
I did not understand this comment.  I can't use my syntax to check the first character is one of B, S or F?
 
// ******* The result of a logical OR of non-zero characters will be TRUE, probably defined as -1


#92
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 11:51:31 (permalink)
+1 (1)
There are still some problems. Here is one of them:
if ((Command[0] = 'B' || 'S' || 'F') && (Command[1] = ' ') )

It should be:
if ( Command[0] == 'B' || Command[0] == 'S' || Command[0] == 'F') && (Command[1] ==  ' ') )

Note the "==" for logical equality, rather than assignment, and the multiple comparisons.
 
I suggest you use the simulator to test portions of your code. I have not been able to get the simulator to read a sequence of characters from a file, as is possible with the ADRES register, so you may need to put a breakpoint in the loop and manually change RCREG to simulate serial input. You could also temporarily change EUSART_Read() to ADC_Read() and have the characters in a stimulus file.
 
I tried to find examples of simulator usage for serial input, but only found:
 
https://www.microchip.com/forums/m1007824.aspx
 
http://microchipdeveloper.com/mcu1101:project-12
 
https://www.microchip.com/forums/m821070.aspx
 
http://www.piclist.com/techref/microchip/mplab/sti-rs232.htm
 

 
#93
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 11:53:57 (permalink)
0
PStechPaul
It should be:
if ( Command[0] == 'B' || Command[0] == 'S' || Command[0] == 'F') && (Command[1] ==  ' ') )

 


 Ah.  The assignment was stupid. 
#94
SGK
Senior Member
  • Total Posts : 158
  • Reward points : 0
  • Joined: 2018/05/14 13:55:08
  • Location: 0
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 18:06:51 (permalink)
0
I'm sure there are more elegant ways of doing this but here goes.  I don't want to rely on strlen because even if someone puts in a 3 or four digit number for a temp I want to extract just 2 characters and I chose the first two after the space. (So "S 100<enter>" would set Over_Temp to 10.) Of course I then don't want to place 10 at the first two places of a string of initialised as 0000, and get 1000 converted to Over_Temp.
 
One obvious flaw - even if I have the logic  and code correct - is that the below does not check that cmd[2-3-4-5] are indeed numbers. I guess that could be added to where I have the comment "Check command for input errors." I haven't thought of a short way to add that to the if statement yet. 
 
For initial testing I was thinking that rather than try to learn to use the simulator I could flash a PIC and then use my USB to UART TTL cable and connect to pins 1 (Vdd), 5 (Rx), 10 (Tx), and 20 (GND).  I could slip a few header pins into my universal programming seat to make the connections easy. 
 

//Program key constants
void Program_Constants(void)
{
Send_Programming_String;
char Cmd[]="000000";
char Cmd_Val[] = "0000";
int i=0;
int Shift = 2;
int Extract_Num;
char Input_Char = '£';
while (Input_Char != 'X') { //Process multiple commands until X
while (Input_Char != 'X' && i < 6 && Input_Char != '\r'){ //Read up to 6 characters only and stop early if X or \r.
Input_Char = EUSART_Read();
Cmd[i] = Input_Char;
i++;
}
i=0;
if (Input_Char != 'X') { //Examine and process command. Skip if X was entered.
if ((Cmd[0] == 'B' || Cmd[0] == 'S' || Cmd[0] == 'F') && (Cmd[1] == ' ')){ //Check command for input errors.
if (Cmd[0] = 'B') {
Extract_Num = 4;
Shift = -1;}
else {
Extract_Num = 2;
Shift =0;
}
while (Extract_Num >=1){
Cmd_Val[Extract_Num + Shift] = Cmd[Extract_Num-Shift];
Extract_Num--;
}
switch (Cmd[0]) {
case 'B': NTC_Beta = atoi(Cmd_Val);
break;
case 'S': Over_Temp = atoi(Cmd_Val);
break;
case 'F': DC50_Limit = atoi(Cmd_Val);
break;
}
Send_Programming_String;
}
else {
printf("INPUT ERROR\n\n");
Send_Programming_String;
}
}

}

}

#95
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 18:44:35 (permalink)
0
I think

Send_Programming_String;
is meant to be
Send_Programming_String();
 

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
#96
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 19:16:43 (permalink)
0
I found an easy way to simulate the serial port:




char    RXDsim[] = {'B',' ','1','2','3','4','\n','X','\0'};
int     RXDptr = -1;

char    EUSART_Read(void) {
//    while(!RCIF);
//    return  RCREG;
    if(RXDptr < sizeof(RXDsim))
        RXDptr++;
    else
        RXDptr = 0;
    return RXDsim[RXDptr];
    }


Also, you can make the atoi() function read just the first two characters by setting the appropriate member of the array to zero. So for command[] = "S 5678" set command[4]=0, which terminates the string, and then atoi(command) will return 56.




 
#97
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 19:19:20 (permalink)
0
I was unable to post using Internet Exploder on my Win10 machine. This is from my old Win8 machine with Firefox.

 
#98
PStechPaul
Super Member
  • Total Posts : 2558
  • Reward points : 0
  • Joined: 2006/06/27 16:11:32
  • Location: Cockeysville, MD, USA
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 23:11:30 (permalink)
0
So it seems that I can only post using "Full Version" now. It would sure be nice to be able to concentrate on actually solving problems with PIC programming and related issues, instead of fighting the frivolities of an erratic and dysfunctional forum. Oh, well, apparently we are not seen as generating revenue, so our complaints have lowest priority.
 
Anyway, I thought I'd post what I came up with for a command parser:

#include    <xc.h>
#include    <string.h>
#include    <stdlib.h>
int get_temp( int adc );
int adcval[] = { 906,890,868,836,795,743,682,613,540,468,399 };
__eeprom    int tempC[] = { 0,10,20,30,40,50,60,70,80,90,100 };
void Program_Constants(void);
void    Send_Programming_String();
volatile char    SERCHAR = '0';
int     NTC_Beta = 1800;
int     Max_TempC = 25;
volatile char    Command[8];
char    RXDsim[] = {'B',' ','1','2','3','4','\r','S',' ','7','6','5','\r', 'X','\r'};
int     RXDptr = -1;
char    EUSART_Read(void) {
//    while(!RCIF);
//    return  RCREG;
    if(RXDptr < sizeof(RXDsim)-1)
        RXDptr++;
    else
        RXDptr = 0;
    return RXDsim[RXDptr];
    }

void main(void)
{
int readadc, readC;
    CREN=1; SYNC=0; SPEN=1;
    ANSELA=0; ANSELC=0;
    while(1) {
        for(readadc = 900; readadc > 468; readadc -= 20)
            readC = get_temp(readadc);
        Program_Constants();
    }
}
void Program_Constants(void)
{
 //Send_Programming_String;
 int count=0;
 char Input_Char = '£';
 strcpy( Command, "" );
 char *ptr;
 while(count < 8) {
   Input_Char = EUSART_Read();
   if(Input_Char == ' ' || (Input_Char >= '0' && Input_Char < 'X') )
       Command[count] = Input_Char;
   if(Input_Char == 'X' || Input_Char == '\r')
       break;
   count++;
    }
 switch(Command[0]) {
    case 'X':   NOP();
                break;
    case 'B':   Command[6]=0;
                ptr = strtok(Command, " ");
                NTC_Beta = atoi( ptr+2 );
                break;
    case 'S':   Command[4]=0;
                ptr = strtok(Command, " ");
                Max_TempC = atoi( ptr+2 );
                break;
    default:    Send_Programming_String();
    }
  NOP();
}
int get_temp( int adc )
{
    int offset, temp, temp1, temp2;
    for(offset=1; offset<10; offset++) {
        if( adcval[offset] < adc) {
            temp1 = tempC[offset-1];
            temp2 = tempC[offset];
            temp = temp1 + ((temp2-temp1)*(adcval[offset-1]-adc))/(adcval[offset-1]-adcval[offset]);
            return temp;
        }
    }
    return -1;
}
void    Send_Programming_String()
{
    NOP();
}


 
#99
qɥb
Monolothic Member
  • Total Posts : 3332
  • Reward points : 0
  • Joined: 2017/09/09 05:07:30
  • Location: Jupiter
  • Status: offline
Re: Newbie: controlling duty cycle of PWM set up with MCC 2018/05/23 23:15:04 (permalink)
0
Does TempC need to be 16 bit?

This forum is mis-configured so it only works correctly if you access it via https protocol.
The Microchip website links to it using http protocol. Will they ever catch on?
PicForum "it just works"
Page: < 12345.. > >> Showing page 5 of 14
Jump to:
© 2020 APG vNext Commercial Version 4.5