Calculate DAC output as decimal value - arm

I'm confused with the method of calculating DAC output as decimal value. I'm using DAC7741. The voltage I need to estimate is called Vint. The below code is a sample I refer. But I don't know why voltage = DAC_buf *3052 ?? I checked the DAC7741 datasheet but didn't see any clue of 3052. Please explain to me how we can get that formula. Thank you!
unsigned long DAC_buf =0x0000;
unsigned char idata Vint_H _at_ 0xB3;
unsigned char idata Vint_L _at_ 0xB4;
DAC_buf += Vint_H;
DAC_buf = DAC_buf << 8;
DAC_buf += Vint_L;
if(Vint_H<0x80)
{
DAC_buf = 0x8000-DAC_buf;
voltage = DAC_buf *3052;
voltage_ten_thousand = (voltage%100000000)/10000000;
voltage_thousand = (voltage%10000000)/1000000;
voltage_hundred = (voltage%1000000)/100000 ;
voltage_ten = (voltage%100000)/10000 ;
voltage_unit = (voltage%10000)/1000;
}
else
{
DAC_buf = DAC_buf- 0x8000;
voltage = DAC_buf *3052;
voltage_ten_thousand = (voltage%100000000)/10000000;
voltage_thousand = (voltage%10000000)/1000000;
voltage_hundred = (voltage%1000000)/100000 ;
voltage_ten = (voltage%100000)/10000 ;
voltage_unit = (voltage%10000)/1000;
}
Another voltage I need to calculate from a power IC (LTC2606).
voltage = 13050- OVSS_buf*100; // OVSS_buf is the hex value assigned to the power IC
I got that formula after tried & error several times. Even though I got correct result to display on the monitor, I still don't know how to get the correct formula. I checked LTC2606 the formula of Vout = (k/2^16)*Vcc. Vcc = 3V
I would appreciate if someone can explain to me the way of calculating both voltages I mentioned above.

Related

Programming a PID controller in c language to control the inrush current of a dc motor

I am here to seek help from the community to develop a program in C language that would allow me to limit the inrush current of a DC motor while controlling the PWM at these terminals.
The motor in question is a 50W 24V and I want to limit the current to 2.5A.
For that, I developed an electronic board with a microcontroller from STMicroelectronics, the STM32F31C4T6.
The current measurement is done with an adc.
When I arrive in the function of the PID I am lost, I do not know how to limit the current and at the same time manage the PWM
Here is the beginning of the code I wrote, it just misses the PWM that I send at the beginning as an argument of the function :
#include "PID.h"
/* constants for PID */
const float Kp = 0.01; // The value for Proportional gain
const float Ki = 0.01; // The value for Integral gain
const float Kd = 0.001; // The value for Differential gain
const int Set_Point = 1950; // The ADC reference point we are aiming to regulate to
uint32_t tabDuty[50];
int i =0;
void PWM_Duty_Change(current)
{
/* Global Variables for PID */
float d_Temp = 0; // This stores the old ADC value
float i_Temp = 0; // This stores the accumulated Integral value
float PWM_Temp = 0;
//Local variables for PID
float iMax = 100; // Used to prevent integral wind-up
float iMin = -100; // Used to prevent integral wind-up
float Err_Value; // Holds the calculated Error value
float P_Term; // Holds the calculated Proportional value
float I_Term; // Holds the calculated Integral value
float D_Term; // Holds the calculated Differential value
int new_current_ADC_value; // Holds the new ADC value
float PWM_Duty; // Holds the new PWM value
new_current_ADC_value = current;
Err_Value = (Set_Point - new_current_ADC_value);
// This calculates Proportional value, Kp is
//multiplied with Err_Value and the result is assigned to P_Term
P_Term = Kp * Err_Value;
// Prepare Integral value, add the current error
//value to the integral value and assign the total to i_Temp
i_Temp += Err_Value;
// Prevents integral wind-up, limits i_Temp
//from getting too positive or negative
if (i_Temp > iMax)
{i_Temp = iMax;}
else if (i_Temp < iMin)
{i_Temp = iMin;}
// Calculates the Integral value, Ki is
//multiplied with i_Temp and the result is assigned to I_Term
I_Term = Ki * i_Temp;
// Calculates Differential value, Kd is multiplied with
//(d_Temp minus new_ADC_value) and the result is assigned to D_Term
// The new_ADC_value will become the old ADC value
//on the next function call, this is assigned to d_Temp so it can be used
D_Term = Kd * (d_Temp - Err_Value);
d_Temp = Err_Value;
/****** Now we have the P_Term, I_Term and D_Term *****/
PWM_Duty = PWM_Temp - (P_Term + I_Term + D_Term);
// PWM overflow prevention
if (PWM_Duty > 90)
{PWM_Duty = 90;}
else if (PWM_Duty < 10)
{PWM_Duty = 10;}
// Adjusts the PWM duty cycle
adjust_PWM(PWM_Duty);
// Assigns the current PWM duty cycle value to PWM_Temp
PWM_Temp = PWM_Duty;
}
If you need more information do not hesitate to ask me.
I thank you for all the help you can give me

"No source code lines were found at current PC 0x74e." with double in MPLAB X

Need some help with a simple calculation done on a PIC24FJ128GB204.
Using MPLAB X 5.2, XC16 compiler, ICD4.
I have a sensor that returns data in 6 bytes: [temp MSB][temp LSB][CRC][humidityMSB][humidityLSB][crc]
Formula for the temp (RC = raw counts): T(deg C) = -45 +175*(RC/(2^16-1))
As too often is the case, I had it working correctly, but somehow changed something and cannot find the issue.
My function:
int8_t SHT31_ConvertData( uint8_t MeasurementData[],
int16_t * TempResult,
uint8_t * RHResult){
// converts data from raw counts to temp (deg C) and RH (%)
// __attribute__((aligned(2))) double TempCelcius = 0;
double TempCelcius = 0;
uint16_t TempRaw,RHRaw = {0};
double RH = 0;
// combine both bytes to get raw temperature value
TempRaw = (MeasurementData[0] << 8);
TempRaw += MeasurementData[1];
TempCelcius = TempRaw;
TempCelcius /= 0xFFFF;
TempCelcius *= 175;
TempCelcius -= 45;
TempCelcius *= 100;
*TempResult = (int)TempCelcius;
// combine both bytes to get raw relative humidity value
RHRaw = (MeasurementData[3] << 8);
RHRaw += MeasurementData[4];
RH = RHRaw;
RH /= 0xFFFF;
RH *= 100;
*RHResult = RH;
return 1;
}
While debugging I sometimes (say 50% of the time) have an issue with the calculations, most often at the
TempCelcius = TempRaw; or TempCelcius /= 0xFFFF; lines.
The debugger console will have lines such as "No source code lines were found at current PC 0x74e. Open program memory view to see instruction code disassembly."
The instruction for that address in the program memory would be (for example) ADD W8, W8, W8. There would always be a command at that memory location.
I don't have enough background yet to solve this myself, so far I found the following possible causes:
Vcap with too high an ESR (checked)
WDT on (checked, HW also disabled in pragmas)
Unhandled interrupt (added _DefaultInterrupt with breakpoint to check)
Accessing word or long at an odd address (thus address error exception) (don't really understand this completely. Tried __attribute__((aligned(2))) double TempCelcius = 0; hoping to align.)
Division by 0 (not the case, I think)
Bad initialized pointers (given my proficiency in C, that could be the case, but I don't use pointers in that part of code)
SFR window open while debugging (is closed.)
What could be the issue? If necessary, will post pragmas, memory map, ...

Adding values to matrix from a single variable in matlab

I have a problem where i can't add values to my 1 x 250 matrix directly from a variable. This is the code.
COMPORT = 'COM4';
BAUDRATE = 115200;
s1 = serial(COMPORT, 'baudrate', BAUDRATE);
set(s1, 'Terminator', 10);
fopen(s1);
adc = 0;
N = 250;
values = zeros(1, N);
for n = 1:N
adc = fscanf(s1);
values(n) = adc;
flushinput(s1);
flushoutput(s1);
end
x = linspace(0, 250);
plot(x, n);
The values(n) = adc does not seem to work and i don't know how to work my way around it.
This doesn't work because values(n) is a single element and the output from fscanf(s1) consist of several elements.
Maybe you want to use cells?
values{n} = adc;
Substitute the pre-allocation: n = zeros(1, N) with n = cell(1,N);.
Notice that you need to do some changes later in your code. I'll leave that uo to you.

Can't extract an integer from a thermometer byte reading

Afternoon all,
Apologies if this question is in the wrong format or in the wrong place, if this is the case, please flag and I'll change it or take it elsewhere.
I am using a development board to send a temperature reading to an LCD panel and I am really struggling to comprehend as to why the temperature at the moment that the program is run isn't being printed onto my LCD. A lot of the code is from framework given to me and is correct as far as I can tell.
My question stems from these functions:
uch get_temp()
{
int i;
DQ_HIGH();
reset(); //reset,wait for 18b20 responsion
write_byte(0XCC); //ignore ROM matching
write_byte(0X44); //send temperature convert command
for(i=20;i>0;i--)
{
//display(); //call some display function,insure the time of convert temperature
}
reset(); //reset again,wait for 18b20 responsion
write_byte(0XCC); //ignore ROM matching
write_byte(0XBE); //send read temperature command
TLV=read_byte(); //read temperature low byte
THV=read_byte(); //read temperature high byte
DQ_HIGH(); //release general line
TZ=(TLV>>4)|(THV<<4)&0X3f; //temperature integer
TX=TLV<<4; //temperature decimal
if(TZ>100)
{
TZ/100;
} //not display hundred bit
ge=TZ%10; //integer Entries bit
shi=TZ/10; //integer ten bit
wd=0;
if (TX & 0x80)
wd=wd+5000;
if (TX & 0x40)
wd=wd+2500;
if (TX & 0x20)
wd=wd+1250;
if (TX & 0x10)
wd=wd+625; //hereinbefore four instructions are turn decimal into BCD code
shifen=wd/1000; //ten cent bit
baifen=(wd%1000)/100; //hundred cent bit
qianfen=(wd%100)/10; //thousand cent bit
wanfen=wd%10; //myriad cent bit
NOP();
return TZ;
}
I have modified this function so that it should return the temperature integer (unsigned char TZ)
This function is then called here:
void Init_lcd(void)
{
ADCON1 = 0x07; //required setting of analog to digital
uch Temp;
TRISD = 0x00;
TRISA1 = 0;
TRISA2 = 0;
TRISA3 = 0;
writeCommand(0x0f);
writeCommand(0x38); //set to two line mode
clearDisplay();
writeString("MAIN MENU");
Temp = get_temp();
writeString(Temp);
writeCommand(0xC0); //change cursor line
}
It isn't printing anything after "MAIN MENU", which obviously means I'm doing something wrong. I can provide further clarification/code on request.
I should probably mention that I am NOT only simply looking for an answer of "paste this in and it'll work". Any feedback in which I understand my mistake and how to fix it is greatly appreciated.
Thanks in advance!
EDIT:
A few people are asking about my writing functions so for further clarification I'll paste them here:
void writeChar(unsigned char ch)
{
lcd = ch;
RS = 1;
RW =0;
E = 1;
lcdDelay();
E=0;
}
void writeString(char *stringToLcd)
{
while(*stringToLcd > 0)
{
writeChar(*stringToLcd++);
}
}
Temp is an unsigned char
uch Temp;
//...
Temp = get_temp();
writeString(Temp);
So, using writeString() will produce undefined results.
You should use write() instead (depending on the library you're using).
But you probably want to convert the return value of get_temp() to an ASCII string first, and display that using writeString().
Update:
void writeString(char *stringToLcd)
This function needs a char*, so you can't provide a single uch.
You need to convert Temp to a string first, using itoa() for example.
I could suggest you to implement a new function
void writeUCH(uch value)
{
unsigned char test = (value >= 100) ? 100 : (value >= 10) ? 10 : 1;
while(test > 0)
{
writeChar((value/test)+'0');
value = value%test;
test /= 10;
}
}
this line:
TZ/100;
will result in no change to TZ
what you really want is this:
TZ = TZ%100;
the value returned from get_temp() is an integer, not a ascii string. I would expect the LCD needs ascii characters, not the binary value of the bytes of an int variable.

One sine-wave vector with different frequencies

I have a vector with many frequencies. Now I try to program a sine-wave, which generates for each frequency one period and put it into one vector... (similar like a sweep signal)
Finally I want to plot this...
I already tried this, but it doesn't work correctly..
%fr = Frequency-Vector with 784 Elements from 2.0118e+04 to 1.9883e+04 Hz
fs = 48000; %Sampling frequency [Hz]
tstart = 0;
tstep = 1/fs;
tend = (length(fr))*(1/min(fr))-tstep;
t3 = tstart3:tstep3:tend3;
sin3 = [];
for i = 1:length(fr)/2
sin3 = [sin3 sin(2*pi*fr(i)*t3)];
end
tstart4 = 0;
tstep4 = 1/fs2;
tend4 = tstep4*length(sin3);
t4 = tstart4:tstep4:tend4-tstep4;
figure;
plot(t4,sin3)
Could you please help me?
Thanks!
If reversed engineer your codes correctly, it seems like you wanted to generate a chirp frequency. It could be more efficient if you do it as follows
fr = linspace(2.0118e4, 1.9883e4, 784); % Frequency content
%fr = linspace(2e4, 1e4, 784); % Try this for a wider chirp
fs = 48e3;
phi = cumsum(2*pi*fr/fs);
s1 = sin(phi);
spectrogram(s1, 128, 120, 128, fs); % View the signal in time vs frequency

Resources