I'm having some troubles about my 7 segment 2 digit counter. I'm using a PIC16F877A with 20Mhz crystal. I'm programming my pic using a replica PICKIT 3 and MPLAB IDE.
Circuit
When i write 02,03,04,04...06 segment displaying it like 88 but 2. Digit C and F segments are not bright as other segments.
02
When i write 01,07,10, everything is normal
My code:
#include <16F877A.h>
#use delay(clock=20m)
#define Dig2 PIN_A0
#define Dig1 PIN_A3
#define rfid PIN_A1
#define reset PIN_A2
#use fast_io(b)
#use fast_io(a)
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
//static const int digit[10]= { 0b0111111, 0b0000110, 0b1011011, 0b1001111,0b1100110,0b1101101, 0b1111101, 0b0000111, 0b1111111, 0b1101111 };// anode
static const int digit[10]= { 0b1000000, 0b1111001, 0b0100100, 0b0110000,0b0011001,0b0010010, 0b0000010, 0b1111000, 0b0000000, 0b0010000 };//cathode
//SECOND CODE
void display(unsigned char value)
{
int onlar = value / 10;
int birler = value % 10;
output_low(Dig2);
output_high(Dig1);
output_b(digit[onlar]);
delay_ms(5);
output_low(Dig1);
output_high(Dig2);
output_b(digit[birler]);
delay_ms(5);
}
/* FIRST CODE
// Written by Michaƫl Roy
void display(unsigned char value)
{
static char tens = 0;
char dig = (tens) ? (value / 10) : (value % 10);
dig = digit[dig];
output_high((tens) ? Dig1 : Dig2);
output_b(dig);
output_low((tens) ? Dig2 : Dig1);
tens = !tens;
} */
void main()
{
char sayi = 0;
set_tris_b(0b10000000);
set_tris_a(0b11111010);
while(1)
{
display(sayi);
if(input(rfid) == 0)
{
sayi++;
while(input(rfid) == 0)
{
display(sayi);
}
if (sayi == 100)
{
sayi = 0 ;
}
}
if(input(reset) == 0)
{
delay_ms(3000);
if(input(reset) == 0)
{
sayi = 0;
}
}
}
}
How can I solve this?
Related
I pass in a hex number into hex2bin and it prints out the binary number correctly but I don't want it to print out the number I want to return the number so I can use it to find the cardinality of the number. How would I store the number instead of printing it out?
int hex2bin (int n){
int i,k,mask;
for(i = sizeof(int) * 8 - 1; i >= 0; i--){
mask = 1 << i;
k = n & mask;
k == 0 ? printf("0"):printf("1");
}
return 0;
}
Perhaps something like this?
int result = 0;
int i, k...
...
result = result | (((k == 0) ? 0 : 1) << i;
...
return result;
Instead of being clever with an int, you could of course also simply use an array of variables instead.
Store the number in a string whose space is provided by a compound literal (Available since C99).
It works like OP's flow: Loop up to sizeof(int) * 8 times, finding the value of 1 bit and print/save it.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
// Maximum buffer size needed
#define UTOA_BASE_2 (sizeof(unsigned)*CHAR_BIT + 1)
char *utoa_base2(char *s, unsigned x) {
s += UTOA_BASE_2 - 1;
*s = '\0';
do {
*(--s) = "01"[x % 2];
x /= 2;
} while (x);
return s;
}
#define TO_BASE2(x) utoa_base2((char [UTOA_BASE_2]){0} , (x))
void test(unsigned x) {
printf("base10:%10u base2:%5s ", x, TO_BASE2(x));
char *s = TO_BASE2(x);
// do stuff with `s`, it is valid for until the end of this block
printf("%s\n", s);
}
int main(void) {
test(0);
test(25);
test(UINT_MAX);
}
Sample output
base10: 0 base2: 0 0
base10: 25 base2:11001 11001
base10:4294967295 base2:11111111111111111111111111111111 11111111111111111111111111111111
This is a variation of this base-n answer.
You can use the strcat function to do that.
Note that the new hex2bin function in this answer assumes that the parameter char *buf has already been allocated and can hold at least 1+sizeof(int)*8 bytes including the null terminator:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// assume: buf is at least length 33
int hex2bin (int n, char *buf)
{
int i,k,mask;
for(i = sizeof(int) * 8 - 1; i >= 0; i--){
mask = 1 << i;
k = n & mask;
k == 0 ? strcat(buf, "0") : strcat(buf, "1");
}
return 0;
}
int main()
{
int n = 66555;
char buffer[1+sizeof(int)*8] = { 0 } ;
hex2bin(n, buffer);
printf("%s\n", buffer);
return 0;
}
I hope you will find this helpful :)
bool convertDecimalBNR(INT32 nDecimalValue, UINT32 * punFieldValue, INT32 nBitCount, DecimalBNRType * pDecimalSpecification)
{
bool bBNRConverted = false;
INT32 nBitIndex = nBitCount - 1;
INT32 nBitValue = anTwoExponents[nBitIndex];
*punFieldValue = 0;
if ((nDecimalValue >= pDecimalSpecification->nMinValue) && (nDecimalValue <= pDecimalSpecification->nMaxValue))
{
// if the value is negative, then add (-1 * (2 ^ (nBitCount - 1))) on itself and go on just like a positive value calculation.
if (nDecimalValue < 0)
{
nDecimalValue += nBitValue;
nBitIndex--;
nBitValue /= 2;
*punFieldValue |= BIT_0_ONLY_ONE;
}
while (nBitIndex >= 0)
{
*punFieldValue = (*punFieldValue << 1);
if (nDecimalValue >= nBitValue)
{
nDecimalValue -= nBitValue;
*punFieldValue |= BIT_0_ONLY_ONE;
}
nBitIndex--;
nBitValue /= 2;
}
if (nDecimalValue <= nBitValue)
{
bBNRConverted = true;
}
}
return (bBNRConverted);
}
When I try to run this code it just posts the output after the exit function I don't why it just doesnt work. I know the code is long because I am making a game whilst learning OpenGL, and I am trying to make it cross-platform as possible.The line 80 isnt executed until the window is closed.
Can someone figure out and fix the problem , or is it because of my weird game design?
If its a compatibility issue here are the specs:
ArchLinux(x86_64) with xfce4
the compiler is gcc
#include <GL/glut.h>
#include <stdio.h>
#ifdef WIN32 // Will need this later
#include <io.h>
#include <windows.h>
#elif _POSIX_C_SOURCE >= 199309L
#include <time.h> // for nanosleep
#include <unistd.h>
#else
#include <unistd.h> // for usleep
#endif
/**
By default it should be
UP - move on negative z axis
DOWN - move on positive z axis
LEFT - move left relative to the camera (mostly negative x axis)
RIGHT - move right relative to the camera (mostly positive x axis)
SPACE - jump (fxp. decreasing the Z value)
**/
unsigned char controls[5],areyougoingtoexit;
unsigned char configurationdone,ingame = 0;
FILE *configuration;
unsigned short displayx,displayy,displaymode;
int winIDMain;
void mainmenurender(void);
void mainmenukeyboard(unsigned char c, int x, int y);
void mainmenumouse(int button, int state, int x, int y);
idle(void){ //To prevent compilation errors ,thats why I puted it infront of the code
glutSetWindow(winIDMain);
glutPostRedisplay();
}
int main(int argc, char* argv) {
while(1){
if(configurationdone){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(displayx, displayy);
winIDMain = glutCreateWindow("GL Game");
if(ingame == 0){
glutSetWindow(winIDMain);
glutDisplayFunc(mainmenurender);
glutKeyboardFunc(mainmenukeyboard);
glutMouseFunc(mainmenumouse);
glutIdleFunc (idle);
}
if(displaymode == 1){
glutFullScreen();
}
glutMainLoop();
}else{
loadconfiguration();
}
}
}
void mainmenukeyboard(unsigned char c, int x, int y) {
if (c == 27) {
if(displaymode == 1)
displaymode == 0;
else
displaymode == 1;
}
}
void mainmenumouse(int button, int state, int x, int y) {
int perpartpixels = glutGet(GLUT_WINDOW_HEIGHT) / 40; //Aproxx 5% of the resolution
if (button == GLUT_LEFT_BUTTON){
printf("X:%d Y:%d",x,y);
if((y >= perpartpixels * 3 && y <= perpartpixels * 3 + 15) && (x >= 0 && x <= 81)){
printf("Play");
}else if((y >= perpartpixels * 4 && y <= perpartpixels * 4 + 15) && (x >= 0 && x <= 72)){
printf("Settings");
}else if((y >= perpartpixels * 5 && y <= perpartpixels * 5 + 15) && (x >= 0 && x <= 36)){
exit(0);
}
}
if (button == GLUT_RIGHT_BUTTON) {
exit(0);
}
}
void mainmenurender(void) {
glutSetWindow(winIDMain);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity ();
char mainmenustring[9] = "Main Menu";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.9);
int mainmenulen, mainmenui;
mainmenulen = (int)strlen(mainmenustring);
for (mainmenui = 0; mainmenui < mainmenulen; mainmenui++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, mainmenustring[mainmenui]);
}
char startstring[5] = "Start";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.8);
int startlen, starti;
startlen = (int)strlen(startstring);
for (starti = 0; starti < startlen; starti++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, startstring[starti]);
}
char settingsstring[8] = "Settings";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.75);
int settingslen, settingsi;
settingslen = (int)strlen(settingsstring);
for (settingsi = 0; settingsi < settingslen; settingsi++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, settingsstring[settingsi]);
}
char exitstring[9] = "Exit";
glColor3f(1, 1, 1);
glRasterPos2f(-1, 0.7);
int exitlen, exiti;
exitlen = (int)strlen(exitstring);
for (exiti = 0; exiti < exitlen; exiti++) {
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, exitstring[exiti]);
}
glutSwapBuffers();
}
// Load config functions
int loadconfiguration(void) {
//Default variables
char defaultcontrolconfig[5] = { 0x18, 0x19, 0x1A, 0x1B, 0x20 }; //UP,DOWN,LEFT,RIGHT,SPACE(JUMP)
unsigned short defaultx = 640,defaulty = 480,defaultmode = 0; //X RES,Y RES, FULLSCREENMODE (0 NO ,1 YES)
//Check if config folder is present otherwise create it
int result = mkdir("configuration", 0777);
if(result == -1){
printf("Ignore creating folder:\nError -1 Directory already exists\n");
}else if(result != 0){
printf("Error: %d while creating configuration folder\n", result);
}
//Check if control configuration is present otherwise create it
if (access("configuration/controls.conf",F_OK)!= -1)
{
printf ("Found controls configuration file\n");
configuration = fopen("configuration/controls.conf", "rb");
}
else
{
configuration = fopen("configuration/controls.conf", "wb");
fwrite(defaultcontrolconfig,1,5,configuration);
}
fread(controls,1,5,configuration);
printf("Finished loading controls configuration\n");
fclose(configuration);
//Check if display configuration is present otherwise create it
if (access("configuration/display.conf",F_OK)!= -1)
{
printf ("Found display configuration file\n");
configuration = fopen("configuration/display.conf", "rb");
}
else
{
configuration = fopen("configuration/display.conf", "wb");
fprintf(configuration,"%hd\n%hd\n%hd",defaultx,defaulty,defaultmode);
}
rewind(configuration);
fscanf(configuration,"%hd\n%hd\n%hd",&displayx,&displayy,&displaymode);
printf("Finished loading display configuration\n");
fclose(configuration);
printf("Finished loading configurations\n");
configurationdone = 1;
return 0;
}
I figured it out myself.The program can only output in glut Display Function (what am I actually talking about is glutDisplayFunc();).
I am trying to get a rotary encoder to control the speed of a 7 segment display counting from 0-9 with the Atmel (ATmega328P Xplained mini) microprocessor. My problem is that whenever I run the program the display just counts faster and faster until you can just see an "8", sometimes it seems that I can keep the speed down by turning the rotary encoder CCW and sometimes no effect at all. As I am not that experienced in programming and especially not this stuff I hope someone is capable and willing to help.
Here is my code:
#include <avr/io.h>
void Display (uint8_t x)
{
static uint8_t tabel[] =
{0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10010000};
PORTD = tabel[x];
}
int GetInput (void)
{
uint8_t x = PINC&1;
uint8_t y = (PINC>>1)&1;
if (x == 0 && y == 0) {return 0; }
else if (x == 1 && y == 0) {return 1;}
else if (x == 0 && y == 1) {return 2;}
else {return 3;}
}
int main(void)
{
DDRD = 0xFF; // set PortD as an output
DDRC = 0x00; // set PortC as an input
PORTB = 0x03; // Activate Pull-up resistors
float d = 9000;
int tick = 0;
int i = 0;
int input, state = 0; // initial state
int oldInput = 0;
while (1)
{
input = GetInput();
if (oldInput == 0 && input == 1)
{
d = (d * 1.1);
//slower
}else if (oldInput == 0 && input == 2)
{
d = (d * 0.9);
//faster
}else if (oldInput == 1 && input == 0)
{
d = (d * 0.9);
//faster
}else if (oldInput == 1 && input == 3)
{
d = (d * 1.1);
//slower
}else if (oldInput == 2 && input == 0)
{
d = (d * 1.1);
//slower
}else if (oldInput == 2 && input == 3)
{
d = (d * 0.9);
//faster
}else if (oldInput == 3 && input == 1)
{
d = (d * 0.9);
//faster
}else if (oldInput == 3 && input == 2)
{
d = (d * 1.1);
//slower
}
oldInput = input;
switch (state)
{
case 0: //ini
Display(0);
state = 1;
break;
case 1: //count
if (i == 9)
{
i = 0;
Display(i);
}
else
{
i++;
Display(i);
}
state = 2;
break;
case 2: // delay
if (tick < d)
{
state = 2;
tick++;
}
else
{
state = 1;
tick = 0;
}
break;
case 3: //reset / destroy
break;
}
}
}
First try changing the GetInput function to return a more useful value. Note that bit 0 and bit 1 of PINC already combine to form the integer that you're reconstructing.
int GetInput (void)
{
// array to convert grey scale bit patterns to direction indicators.
// Rows indexed by lastValue, columns indexed by thisValue, and the
// content is -1 for CCW, +1 for CW, 0 for no motion. Note that 0 is
// also used for an invalid transition (2 bits changed at once), but a
// different value could be used for fault detection.
static const int tableGreyToDirection[4][4] =
{
0 , -1, 1 , 0 , // lastValue==0
1 , 0 , 0 , -1, // lastValue==1
-1, 0 , 0 , 1 , // lastValue==2
0 , 1 , -1, 0 // lastValue==3
};
static uint8_t lastValue = 0; // A valid default starting value
uint8_t thisValue = (PINC & 0b00000011); // Use the bottom two bits as a value from 0..3
int result = tableGreyToDirection[lastValue][thisValue];
lastValue = thisValue;
return result;
}
You can then simplify the test in the loop greatly.
while (1)
{
// Check the direction of the encoder: -1 = CCW, +1 = CW, anything else = no motion.
input = GetInput();
if(0 < input)
{
// Motion is CW, so increment the delay (within reasonable bounds).
if(8900 > d) d += 100;
}
else if(0 > input)
{
// Motion is CCW, so decrement the delay (within reasonable bounds).
if(100 < d) d -= 100;
}
// Keep the rest as it is...
}
It would be advisable to change d to be a uint16_t and tidy it up a little. Further tips include using #define to provide readable names for constants. E.g. in my table of directions you could use:
#define ENCODER_CW 1
#define ENCODER_CCW -1
#define ENCODER_NEITHER 0
...
static const int tableGreyToDirection[4][4] =
{
ENCODER_NEITHER, ENCODER_CCW, ENCODER_CW, ENCODER_NEITHER, // lastValue==0
...
I'm sure you can fill it out yourself.
I checked your SW, but I can't find big issue instantly.
You'd better check below part.
If you didn't touch the encoder but speed is faster and faster
: do you have a scope to check the encoder input port whether noise is input from the port or not.
If two input port is stable, please check your value also stable
: old input and new input value should be same
: check by log or output toggle unused port when the value is changed. you can debug your own code.
You'd better add amount tick value than multiply directly to prevent d value becomes 0.
your CPU has to run as fast as detect port status change in main loop. - I think it is possible if this code is all of your system.
I'm trying to use u8glib on an arduino ethernet, in the first phase i need to display a simple countdown so in a little pretty way. To test if the display can be managed in time.
I have to measure changes in order of milliseconds, likes 30ms, therefore i need that the countdown changes 1 units in about 50/100ms.
This is the oled http://www.seeedstudio.com/wiki/Grove_-_OLED_Display_1.12%22
Now im trying U8glib because has a lot of font integrated and it seems well documented.
But the big problem is: The countdown, without sleep obiuvsly, is too slow! In order of 1 change in 1second.
What i'm wrong? I need to change library?
Thanks
This is the code
#include "U8glib.h"
U8GLIB_SSD1327_96X96_GR u8g(U8G_I2C_OPT_NONE); // I2C
#define MAX_VAL 200
#define MAX_VAL1 250
#define MAX_VAL2 350
#define MAX_VAL3 450
#define MAX_VAL4 500
int current_max_val = MAX_VAL1;
int currentBB = current_max_val;
char bb_n[4] = {0,0,0,0};
int bb_level = 4;
static int last_bb_n = current_max_val;
void draw(void) {
int sizev = u8g.getStrWidth(bb_n);
u8g.drawStr( (48 - (sizev/2)),60,bb_n);
for(int i=0;i<bb_level;i++){
u8g.drawTriangle((i*10)+0,90, (i*10)+10,90, (i*10)+5,85);
}
last_bb_n = currentBB;
u8g.drawHLine(0,20, 96);
u8g.drawHLine(0,70, 96);
}
void setup(void) {
// flip screen, if required
//u8g.setRot180();
// set SPI backup if required
//u8g.setHardwareBackup(u8g_backup_avr_spi);
// assign default color value
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255); // white
}
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3); // max intensity
}
else if ( u8g.getMode() == U8G_MODE_BW ) {
u8g.setColorIndex(1); // pixel on
}
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255,255,255);
}
u8g.setFont(u8g_font_gdb30);
}
void loop(void) {
// picture loop
u8g.firstPage();
count();
do {
draw();
} while( u8g.nextPage() );
}
void count(){
if(currentBB == 0){
currentBB = current_max_val;
}
itoa(currentBB,bb_n,10);
if(currentBB >= ((current_max_val/4)*3)){
bb_level = 4;
}else if((currentBB < ((current_max_val/4)*3)) && (currentBB >= (current_max_val/4)*2)){
bb_level = 3;
}else if((currentBB < ((current_max_val/4)*2)) && (currentBB >= (current_max_val/4))){
bb_level = 2;
}else if(currentBB < (current_max_val/4)){
bb_level = 1;
}else{
bb_level = 0;
}
currentBB--;
Some ideas for optimization:
Use U8GLIB_SSD1327_96X96_2X_GR
Make sizev a global variable and calculate its value in count()
Oliver
I am changing the phase of signal from 0 to 360 by each degree to get max voltage value.Because if i change phase of the signal the voltage also changes.I have the fallowing code to find max value.
void Maxphase(float *max, unsigned int *index)
{
*max = 0.0;
float value;
unsigned int i, data;
for (i=0;i<=360;i++)
{
phaseset(i);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > *max) //find max value
{
*max = value; //max voltage
*index = i;
}
}
}
from the above code I am getting Max value(voltage) after 38 sec(360*100) because for every read operation my device needs 100ms delay. This is too large, I can't change hardware thus i want to get the max value within 2 to 3 sec by optimizing software.
then I have tried with the fallowing code.
void Maxphase(float *max1, unsigned int *index1)
{
max = 0.0;
float value;
unsigned int i,j,data;
for (i=0;i<=360;i+=10)
{
phaseset(i);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > max) //find max value
{
max = value; //max voltage
index = i;
}
}
*max1=max;
*index1=index;
for (i=*index1-9;i<=*index1+9;i+=1)
{
j=i;
phaseset(j);
delay_ms(100);
data = readvalue();
value = voltage(mux1);
if(value > *max1) //find max value
{
*max1 = value; //max voltage
*index1 = i;
}
}
}
I have reduced time from 45 sec to 7 sec. i have reduced iterations 360 to 54(54*100). I want to reduce it 7 sec to 2 sec.
Can any one help me with better algorithm that i can get max value from (0 to 360) with in 2 sec.
I have measured the voltage values using scope by changing phase. I have written below how it vary voltage with phase.
Phase (degree) voltage(max)
0 0.9mv
45 9.5mv
90 9.0mv
135 0.9mv
180 292mv
225 601mv
270 555mv
315 230mv
360 0.9mv
I am new to C programming. Can anyone provide sample code for the best algorithm.
Golden section search is probably what you are after. It is effective, but still pretty simple.
If you want something even faster and more sophisticated, you can use Brent's method.
If you can be sure that there is only a single highest point on your 360 degrees you can do a recursive divide and conquer.
You start by looking e.g. at 0, 180, 270. Let's say you find the answer is that 180 + 270 together have the highest value. Than you start by looking in at 210.... Which side is higher? And so on ...
Exploiting the various comments and suggestions here, I present this untested piece of code. I don't know whether this works at all or is an improvement over the existing source, but it was fun to try, anyway:
extern void phaseset(int);
extern void delay_ms(int);
extern float readvalue();
extern float voltage(int);
extern int mux1;
float probe(int phase)
{
float data;
phaseset(phase);
delay_ms(100);
data = readvalue(); /* data is ignored? */
return voltage(mux1); /* mux1? */
}
/* helper routine, find the max in a given range [phase1, phase2] */
void maxphase_aux(int phase1, float vol1, int phase2, float vol2, int *phaseret, float *volret)
{
float xvol1 = 0, xvol2 = 0;
int xphase1 = -1, xphase2 = -1;
/* test the voltage in the middle */
int phasem = abs(phase2 - phase1) / 2;
float volm = probe(phasem);
if (volm > vol1 && volm > vol2) {
/* middle point is the highest so far,
* search left and right for maximum */
*volret = volm;
*phaseret = phasem;
maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
} else if (volm < vol1 && volm > vol2) {
/* vol1 is the highest so far,
* search between volm and vol1 for maximum */
maxphase_aux(phase1, vol1, phasem, volm, &xphase1, &xvol1);
} else if (volm > vol1 && volm < vol2) {
/* vol2 is the highest so far,
* search between volm and vol2 for maximum */
maxphase_aux(phase2, vol2, phasem, volm, &xphase2, &xvol2);
} else {
/* not possible? */
return;
}
if (xvol1 > volm) {
*volret = xvol1;
*phaseret = xphase1;
}
if (xvol2 > volm) {
*volret = xvol2;
*phaseret = xphase2;
}
}
void maxphase(int *phaseret, float *volret)
{
float v0 = probe(0);
float v360 = probe(360);
maxphase_aux(0, v0, 360, v360, phaseret, volret);
}
UPDATE: 2012-11-10.
#include <stdio.h>
#include <string.h>
#include <math.h>
#define FAKE_TARGET 89
unsigned fake_target = FAKE_TARGET;
float probe_one(unsigned int phase);
void Maxphase(float *max, unsigned int *index);
void Maxphase(float *max, unsigned int *index)
{
unsigned int aim, idx, victim;
struct best {
unsigned pos;
float val;
} samples[4] = {{0, 0.0}, };
for (aim = 0;aim < 360;aim += 90) {
idx=aim/90;
samples[idx].pos = aim;
samples[idx].val = probe_one(samples[idx].pos);
if (!idx || samples[idx].val < samples[victim].val ) victim = idx;
}
/* eliminate the weakist postion, and rotate the rest,
** such that:
** samples[0] := lower boundary.
** samples[1] := our best guess
** samples[2] := upper boundary
** samples[3] := scratch/probe element
*/
fprintf(stderr, "Victim=%u\n", victim );
switch(victim) {
case 0: samples[0] = samples[1]; samples[1] = samples[2]; samples[2] = samples[3]; break;
case 1: samples[1] = samples[3]; samples[3] = samples[0]; samples[0] = samples[2]; samples[2] = samples[3]; break;
case 2: samples[2] = samples[1]; samples[1] = samples[0]; samples[0] = samples[3]; break;
case 3: break;
}
/* Calculation is easier if the positions are increasing.
** (We can always perform the modulo 360 if needed)
*/
if (samples[0].pos > samples[1].pos ) samples[1].pos += 360;
if (samples[1].pos > samples[2].pos ) samples[2].pos += 360;
while( 1) {
int step;
step = samples[2].pos - samples[0].pos;
if (step < 3) break;
do {
fprintf(stderr, "\n[%u %u %u] Diff=%d\n"
, samples[0].pos , samples[1].pos , samples[2].pos , step);
if (step > 0) step++; else step--;
step /= 2;
aim = (samples[0].pos + step ) ;
/* avoid hitting the middle cell twice */
if (aim %360 != samples[1].pos %360) break;
step += 1;
aim = (samples[0].pos + step ) ;
if (aim %360 != samples[1].pos %360) break;
step -= 2;
aim = (samples[0].pos + step ) ;
break;
} while(0);
fprintf(stderr, "Step=%d Aim=%u, Idx=%u\n",step, aim,idx );
samples[3].pos = aim;
samples[3].val = probe_one( samples[3].pos );
victim= (samples[3].pos > samples[1].pos ) ? 2 : 0;
if (samples[3].val > samples[1].val) idx= 1; else idx = victim;
fprintf(stderr, "Victim=%u, TargetIdx=%u\n", victim, idx );
/* This should not happen */
if (samples[3].val < samples[victim].val) break;
if (idx != victim) samples[2-victim] = samples[idx];
samples[idx] = samples[3];
}
*max = samples[1].val;
*index = samples[1].pos % 360;
}
float probe_one(unsigned int phase)
{
float value;
#ifdef FAKE_TARGET
int dif;
dif = fake_target-phase;
if (dif < -180) dif = 360+dif;
else if (dif > 180) dif = 360-dif;
/* value = 1.0 / (1 + pow(phase-231, 2)); */
value = 1.0 / (1 + pow(dif, 2));
fprintf(stderr, "Target = %d: Probe(%d:%d) := %f\n", fake_target, phase, dif, value );
sleep (1);
#else
unsigned int data;
phase %= 360;
phaseset(phase);
delay_ms(100);
data = readvalue(); // what is this ?
value = voltage(mux1);
#endif
return value;
}
int main(int argc, char **argv)
{
float value;
unsigned int index;
if (argv[1]) sscanf (argv[1], "%u", &fake_target);
fake_target %= 360;
Maxphase(&value, &index) ;
printf("Phase=%u Max=%f\n", index, value );
return 0;
}