Issues in ADC of PIC16F887 reading LM35 temperature value is frequently varying - embedded
I have connected the LM35 temperature sensor in analog channel of AN1 then transmitting the temperature through serial RS232 in PIC16F887. I have read the temperature value but the value is frequently varying as 31 and 32, also when touch the LM35 temperature is varying very fast as 32, 33 and etc. How to control the constant temperature value. Here is my code, Please any one help me.
#include <htc.h>
void main(void)
{
TRISA1 = 1;
ANS1 = 1;
OSCCON = 0x78; // OSCILLATOR CONTROL REGISTER
TXSTA = 0x26;
RCSTA = 0x90;
SPBRG = 10;
ADCON1 = 0x80;
unsigned int current_temp, initial_temp = temperature();
transmit_char(initial_temp);
flag = 0;
while (1)
{
current_temp = temperature();
if((current_temp == (initial_temp + 1)) || (current_temp == (initial_temp - 1)))
{
flag = 1;
}
if(flag == 1)
{
flag = 0;
transmit_char(current_temp);
initial_temp = current_temp;
}
}
}
int temperature(void)
{
ADCON0 = 0xC5;
GODONE = 1;
while(GODONE);
int temp;
temp = (ADRESH << 8) + ADRESL;
temp = temp/2;
return temp;
}
Do this,
Collect ten adc data,
Remove min and max from that values.
sum the remaining 8 ADC values and divide the value by 8.
this should be continuous process, average for every ten samples
note: sampling and averaging should be ... 1 to 10 , next 2 to 11 and 3 to 12. at every reading you will get the adc value. sudden fluctuations also get filtered here.
Hope this helps.. good luck..
Related
BME680 sensor faulty gas reference readings
I have a problem with my BME680 readings. I found example code to collect all the air data and make an air quality score (AIQ) out of that (it goes from 0 to 500). You see in the code bellow that in loop() data is collected and AIQ calculated every 2 seconds, and gas reference is updated/collected on every 5-th reading -> if (getgasreference_count++) % 5 == 0) GetGasReference(); so 5*2 sec= every 10 sec (around 230k ohms). Problem starts here, where I implement this code in my other program which runs website and controls motors. Here data is collected and AIQ calculated once a minute, gas reference is updated/collected on every 5-th reading -> if (getgasreference_count++) % 5 == 0) GetGasReference(); so 5*60 sec= every 300 sec= 5 min. Thats when I'm getting faulty gas reference readings (around 100k ohms) and of course following calculated AIQ is wrong. I'm wondering where the problem is because why it matters when you get new gas reference? I'm thinking that bme.setGasHeater(); function has something to do with it, but I don't know how it is related with gas reference readings? I would be grateful if anybody can explain where the problem is. The working example code is here: #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME680.h> #define SEALEVELPRESSURE_HPA (1013.25) #define YOUR_SENSOR_I2C_ADDRESS 0x76 Adafruit_BME680 bme; // I2C float hum_weighting = 0.25; // so hum effect is 25% of the total air quality score float gas_weighting = 0.75; // so gas effect is 75% of the total air quality score int humidity_score, gas_score; float gas_reference = 2500; float hum_reference = 40; int getgasreference_count = 0; int gas_lower_limit = 10000; // Bad air quality limit int gas_upper_limit = 300000; // Good air quality limit void setup() { Serial.begin(115200); Serial.println(F("BME680 test")); Wire.begin(); if (!bme.begin(YOUR_SENSOR_I2C_ADDRESS)) { Serial.println("Could not find a valid BME680 sensor, check wiring!"); while (1); } else Serial.println("Found a sensor"); // Set up oversampling and filter initialization bme.setTemperatureOversampling(BME680_OS_8X); bme.setHumidityOversampling(BME680_OS_2X); bme.setPressureOversampling(BME680_OS_4X); bme.setIIRFilterSize(BME680_FILTER_SIZE_3); bme.setGasHeater(320, 150); // 320°C for 150 ms // Now run the sensor to normalise the readings, then use combination of relative humidity and gas resistance to estimate indoor air quality as a percentage. // The sensor takes ~30-mins to fully stabilise GetGasReference(); } void loop() { Serial.println("Sensor Readings:"); Serial.println(" Temperature = " + String(bme.readTemperature(), 2) + "°C"); Serial.println(" Pressure = " + String(bme.readPressure() / 100.0F) + " hPa"); Serial.println(" Humidity = " + String(bme.readHumidity(), 1) + "%"); Serial.println(" Gas = " + String(gas_reference) + " ohms\n"); Serial.print("Qualitative Air Quality Index "); humidity_score = GetHumidityScore(); gas_score = GetGasScore(); //Combine results for the final IAQ index value (0-100% where 100% is good quality air) float air_quality_score = humidity_score + gas_score; Serial.println(" comprised of " + String(humidity_score) + "% Humidity and " + String(gas_score) + "% Gas"); if ((getgasreference_count++) % 5 == 0) GetGasReference(); Serial.println(CalculateIAQ(air_quality_score)); Serial.println("--------------------------------------------------------------"); delay(2000); } void GetGasReference() { // Now run the sensor for a burn-in period, then use combination of relative humidity and gas resistance to estimate indoor air quality as a percentage. //Serial.println("Getting a new gas reference value"); int readings = 10; for (int i = 1; i <= readings; i++) { // read gas for 10 x 0.150mS = 1.5secs gas_reference += bme.readGas(); } gas_reference = gas_reference / readings; //Serial.println("Gas Reference = "+String(gas_reference,3)); } String CalculateIAQ(int score) { String IAQ_text = "air quality is "; score = (100 - score) * 5; if (score >= 301) IAQ_text += "Hazardous"; else if (score >= 201 && score <= 300 ) IAQ_text += "Very Unhealthy"; else if (score >= 176 && score <= 200 ) IAQ_text += "Unhealthy"; else if (score >= 151 && score <= 175 ) IAQ_text += "Unhealthy for Sensitive Groups"; else if (score >= 51 && score <= 150 ) IAQ_text += "Moderate"; else if (score >= 00 && score <= 50 ) IAQ_text += "Good"; Serial.print("IAQ Score = " + String(score) + ", "); return IAQ_text; } int GetHumidityScore() { //Calculate humidity contribution to IAQ index float current_humidity = bme.readHumidity(); if (current_humidity >= 38 && current_humidity <= 42) // Humidity +/-5% around optimum humidity_score = 0.25 * 100; else { // Humidity is sub-optimal if (current_humidity < 38) humidity_score = 0.25 / hum_reference * current_humidity * 100; else { humidity_score = ((-0.25 / (100 - hum_reference) * current_humidity) + 0.416666) * 100; } } return humidity_score; } int GetGasScore() { //Calculate gas contribution to IAQ index gas_score = (0.75 / (gas_upper_limit - gas_lower_limit) * gas_reference - (gas_lower_limit * (0.75 / (gas_upper_limit - gas_lower_limit)))) * 100.00; if (gas_score > 75) gas_score = 75; // Sometimes gas readings can go outside of expected scale maximum if (gas_score < 0) gas_score = 0; // Sometimes gas readings can go outside of expected scale minimum return gas_score; }
From this Learn Adafruit page it seems the gas readouts can take up to 30 minutes to stabilize. Gas is returned as a resistance value in ohms. This value takes up to 30 minutes to stabilize! Once it stabilizes, you can use that as your baseline reading. Higher concentrations of VOC will make the resistance lower. and on their first page: We recommend that you run this sensor for 48 hours when you first receive it to "burn it in", and then 30 minutes in the desired mode every time the sensor is in use.
PIC24H Uart send only 4 bits correct - need to split
I am working with the explorer16/32 evb and trying to send data to UART. I tried UART1, UART2 with and without interrupts and got the same problem all the time. It appeared that in order to send 1 byte I need to split it to two 4 bits with shift code: #define FCY 16000000 #define BAUDRATE 9600 #define BRGVAL ((FCY/BAUDRATE)/16)-1 U2MODE = 0; U2STA = 0; U2MODEbits.STSEL = 0; // 1-Stop bit U2MODEbits.PDSEL = 0 ; // No Parity 8 bit data U2MODEbits.ABAUD = 0; // Auto-Baud Disabled U2MODEbits.BRGH = 1; // High Speed Mode U2MODEbits.URXINV = 0; U2STAbits.UTXINV = 0; U2BRG = BRGVAL; // Baud Rate Setting for 9600 U2MODEbits.UARTEN = 1; //Enable UART module U2STAbits.UTXEN = 1; //Enable UART TX unsigned char putU2(unsigned char c) { while (U2STAbits.TRMT == 0) { } while ( CTS); while ( U2STAbits.UTXBF); U2TXREG = c & 0xF; U2TXREG = (c >> 4) & 0xF; return c; } If I am sedning that data splited to 4 bits I can see the data correct on the PC( c# serial port application) But it should not be split into two writes to U2TXREG. I am not 100% sure that the FCY is 16000000 but this is the only value that give me reasonable result. What could be the problem?
For PIC24H, in UART high speed mode ( BRGH = 1 ) to get correct value of BRGVAL you need to divide by 4, not 16. Change the formula on line 3. Also, it is helpful to be 100% sure about clock rate; if you didn't change configuration bits it is likely 8 MHz, not 16.
Determine Position of Most Signifiacntly Set Bit in a Byte
I have a byte I am using to store bit flags. I need to compute the position of the most significant set bit in the byte. Example Byte: 00101101 => 6 is the position of the most significant set bit Compact Hex Mapping: [0x00] => 0x00 [0x01] => 0x01 [0x02,0x03] => 0x02 [0x04,0x07] => 0x03 [0x08,0x0F] => 0x04 [0x10,0x1F] => 0x05 [0x20,0x3F] => 0x06 [0x40,0x7F] => 0x07 [0x80,0xFF] => 0x08 TestCase in C: #include <stdio.h> unsigned char check(unsigned char b) { unsigned char c = 0x08; unsigned char m = 0x80; do { if(m&b) { return c; } else { c -= 0x01; } } while(m>>=1); return 0; //never reached } int main() { unsigned char input[256] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }; unsigned char truth[256] = { 0x00,0x01,0x02,0x02,0x03,0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06, 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08}; int i,r; int f = 0; for(i=0; i<256; ++i) { r=check(input[i]); if(r !=(truth[i])) { printf("failed %d : 0x%x : %d\n",i,0x000000FF & ((int)input[i]),r); f += 1; } } if(!f) { printf("passed all\n"); } else { printf("failed %d\n",f); } return 0; } I would like to simplify my check() function to not involve looping (or branching preferably). Is there a bit twiddling hack or hashed lookup table solution to compute the position of the most significant set bit in a byte?
Your question is about an efficient way to compute log2 of a value. And because you seem to want a solution that is not limited to the C language I have been slightly lazy and tweaked some C# code I have. You want to compute log2(x) + 1 and for x = 0 (where log2 is undefined) you define the result as 0 (e.g. you create a special case where log2(0) = -1). static readonly Byte[] multiplyDeBruijnBitPosition = new Byte[] { 7, 2, 3, 4, 6, 1, 5, 0 }; public static Byte Log2Plus1(Byte value) { if (value == 0) return 0; var roundedValue = value; roundedValue |= (Byte) (roundedValue >> 1); roundedValue |= (Byte) (roundedValue >> 2); roundedValue |= (Byte) (roundedValue >> 4); var log2 = multiplyDeBruijnBitPosition[((Byte) (roundedValue*0xE3)) >> 5]; return (Byte) (log2 + 1); } This bit twiddling hack is taken from Find the log base 2 of an N-bit integer in O(lg(N)) operations with multiply and lookup where you can see the equivalent C source code for 32 bit values. This code has been adapted to work on 8 bit values. However, you may be able to use an operation that gives you the result using a very efficient built-in function (on many CPU's a single instruction like the Bit Scan Reverse is used). An answer to the question Bit twiddling: which bit is set? has some information about this. A quote from the answer provides one possible reason why there is low level support for solving this problem: Things like this are the core of many O(1) algorithms such as kernel schedulers which need to find the first non-empty queue signified by an array of bits.
That was a fun little challenge. I don't know if this one is completely portable since I only have VC++ to test with, and I certainly can't say for sure if it's more efficient than other approaches. This version was coded with a loop but it can be unrolled without too much effort. static unsigned char check(unsigned char b) { unsigned char r = 8; unsigned char sub = 1; unsigned char s = 7; for (char i = 0; i < 8; i++) { sub = sub & ((( b & (1 << s)) >> s--) - 1); r -= sub; } return r; }
I'm sure everyone else has long since moved on to other topics but there was something in the back of my mind suggesting that there had to be a more efficient branch-less solution to this than just unrolling the loop in my other posted solution. A quick trip to my copy of Warren put me on the right track: Binary search. Here's my solution based on that idea: Pseudo-code: // see if there's a bit set in the upper half if ((b >> 4) != 0) { offset = 4; b >>= 4; } else offset = 0; // see if there's a bit set in the upper half of what's left if ((b & 0x0C) != 0) { offset += 2; b >>= 2; } // see if there's a bit set in the upper half of what's left if > ((b & 0x02) != 0) { offset++; b >>= 1; } return b + offset; Branch-less C++ implementation: static unsigned char check(unsigned char b) { unsigned char adj = 4 & ((((unsigned char) - (b >> 4) >> 7) ^ 1) - 1); unsigned char offset = adj; b >>= adj; adj = 2 & (((((unsigned char) - (b & 0x0C)) >> 7) ^ 1) - 1); offset += adj; b >>= adj; adj = 1 & (((((unsigned char) - (b & 0x02)) >> 7) ^ 1) - 1); return (b >> adj) + offset + adj; } Yes, I know that this is all academic :)
It is not possible in plain C. The best I would suggest is the following implementation of check. Despite quite "ugly" I think it runs faster than the ckeck version in the question. int check(unsigned char b) { if(b&128) return 8; if(b&64) return 7; if(b&32) return 6; if(b&16) return 5; if(b&8) return 4; if(b&4) return 3; if(b&2) return 2; if(b&1) return 1; return 0; }
Edit: I found a link to the actual code: http://www.hackersdelight.org/hdcodetxt/nlz.c.txt The algorithm below is named nlz8 in that file. You can choose your favorite hack. /* From last comment of: http://stackoverflow.com/a/671826/315052 > Hacker's Delight explains how to correct for the error in 32-bit floats > in 5-3 Counting Leading 0's. Here's their code, which uses an anonymous > union to overlap asFloat and asInt: k = k & ~(k >> 1); asFloat = > (float)k + 0.5f; n = 158 - (asInt >> 23); (and yes, this relies on > implementation-defined behavior) - Derrick Coetzee Jan 3 '12 at 8:35 */ unsigned char check (unsigned char b) { union { float asFloat; int asInt; } u; unsigned k = b & ~(b >> 1); u.asFloat = (float)k + 0.5f; return 32 - (158 - (u.asInt >> 23)); } Edit -- not exactly sure what the asker means by language independent, but below is the equivalent code in python. import ctypes class Anon(ctypes.Union): _fields_ = [ ("asFloat", ctypes.c_float), ("asInt", ctypes.c_int) ] def check(b): k = int(b) & ~(int(b) >> 1) a = Anon(asFloat=(float(k) + float(0.5))) return 32 - (158 - (a.asInt >> 23))
Efficient algorithm to convert(sum) 128-bit data in q-register to 16-bit data
I have 128-bit data in q-register. I want to sum the individual 16-bit block in this q-register to finally have a 16-bit final sum (any carry beyond 16-bit should be taken and added to the LSB of this 16-bit num). what I want to achieve is: VADD.U16 (some 16-bit variable) {q0[0] q0[1] q0[2] ......... q0[7]} but using intrinsics, would appreciate if someone could give me an algorithm for this. I tried using pair-wise addition, but I'm ending up with rather a clumsy solution.. Heres how it looks: int convert128to16(uint16x8_t data128){ uint16_t data16 = 0; uint16x4_t ddata; print16(data128); uint32x4_t data = vpaddlq_u16(data128); print32(data); uint16x4_t data_hi = vget_high_u16(data); print16x4(data_hi); uint16x4_t data_low = vget_low_u16(data); print16x4(data_low); ddata = vpadd_u16( data_hi, data_low); print16x4(ddata); } It's still incomplete and a bit clumsy.. Any help would be much appreciated.
You can use the horizontal add instructions: Here is a fragment: uint16x8_t input = /* load your data128 here */ uint64x2_t temp = vpaddlq_u32 (vpaddlq_u16 (input)); uint64x1_t result = vadd_u64 (vget_high_u64 (temp), vget_low_u64 (temp)); // result now contains the sum of all 16 bit unsigned words // stored in data128. // to add the values that overflow from 16 bit just do another 16 bit // horizontal addition and return the lowest 16 bit as the final result: uint16x4_t w = vpadd_u16 ( vreinterpret_u16_u64 (result), vreinterpret_u16_u64 (result)); uint16_t wrappedResult = vget_lane_u16 (w, 0);
I f your goal is to sum the 16 bit chunks (modulo 16 bit), the following fragment would do: uin16_t convert128to16(uint16x8_t data128){ data128 += (data128 >> 64); data128 += (data128 >> 32); data128 += (data128 >> 16); return data128 & 0xffff; }
Non repeating random numbers in Objective-C
I'm using for (int i = 1, i<100, i++) int i = arc4random() % array count; but I'm getting repeats every time. How can I fill out the chosen int value from the range, so that when the program loops I will not get any dupe?
It sounds like you want shuffling of a set rather than "true" randomness. Simply create an array where all the positions match the numbers and initialize a counter: num[ 0] = 0 num[ 1] = 1 : : num[99] = 99 numNums = 100 Then, whenever you want a random number, use the following method: idx = rnd (numNums); // return value 0 through numNums-1 val = num[idx]; // get then number at that position. num[idx] = val[numNums-1]; // remove it from pool by overwriting with highest numNums--; // and removing the highest position from pool. return val; // give it back to caller. This will return a random value from an ever-decreasing pool, guaranteeing no repeats. You will have to beware of the pool running down to zero size of course, and intelligently re-initialize the pool. This is a more deterministic solution than keeping a list of used numbers and continuing to loop until you find one not in that list. The performance of that sort of algorithm will degrade as the pool gets smaller. A C function using static values something like this should do the trick. Call it with int i = myRandom (200); to set the pool up (with any number zero or greater specifying the size) or int i = myRandom (-1); to get the next number from the pool (any negative number will suffice). If the function can't allocate enough memory, it will return -2. If there's no numbers left in the pool, it will return -1 (at which point you could re-initialize the pool if you wish). Here's the function with a unit testing main for you to try out: #include <stdio.h> #include <stdlib.h> #define ERR_NO_NUM -1 #define ERR_NO_MEM -2 int myRandom (int size) { int i, n; static int numNums = 0; static int *numArr = NULL; // Initialize with a specific size. if (size >= 0) { if (numArr != NULL) free (numArr); if ((numArr = malloc (sizeof(int) * size)) == NULL) return ERR_NO_MEM; for (i = 0; i < size; i++) numArr[i] = i; numNums = size; } // Error if no numbers left in pool. if (numNums == 0) return ERR_NO_NUM; // Get random number from pool and remove it (rnd in this // case returns a number between 0 and numNums-1 inclusive). n = rand() % numNums; i = numArr[n]; numArr[n] = numArr[numNums-1]; numNums--; if (numNums == 0) { free (numArr); numArr = 0; } return i; } int main (void) { int i; srand (time (NULL)); i = myRandom (20); while (i >= 0) { printf ("Number = %3d\n", i); i = myRandom (-1); } printf ("Final = %3d\n", i); return 0; } And here's the output from one run: Number = 19 Number = 10 Number = 2 Number = 15 Number = 0 Number = 6 Number = 1 Number = 3 Number = 17 Number = 14 Number = 12 Number = 18 Number = 4 Number = 9 Number = 7 Number = 8 Number = 16 Number = 5 Number = 11 Number = 13 Final = -1 Keep in mind that, because it uses statics, it's not safe for calling from two different places if they want to maintain their own separate pools. If that were the case, the statics would be replaced with a buffer (holding count and pool) that would "belong" to the caller (a double-pointer could be passed in for this purpose). And, if you're looking for the "multiple pool" version, I include it here for completeness. #include <stdio.h> #include <stdlib.h> #define ERR_NO_NUM -1 #define ERR_NO_MEM -2 int myRandom (int size, int *ppPool[]) { int i, n; // Initialize with a specific size. if (size >= 0) { if (*ppPool != NULL) free (*ppPool); if ((*ppPool = malloc (sizeof(int) * (size + 1))) == NULL) return ERR_NO_MEM; (*ppPool)[0] = size; for (i = 0; i < size; i++) { (*ppPool)[i+1] = i; } } // Error if no numbers left in pool. if (*ppPool == NULL) return ERR_NO_NUM; // Get random number from pool and remove it (rnd in this // case returns a number between 0 and numNums-1 inclusive). n = rand() % (*ppPool)[0]; i = (*ppPool)[n+1]; (*ppPool)[n+1] = (*ppPool)[(*ppPool)[0]]; (*ppPool)[0]--; if ((*ppPool)[0] == 0) { free (*ppPool); *ppPool = NULL; } return i; } int main (void) { int i; int *pPool; srand (time (NULL)); pPool = NULL; i = myRandom (20, &pPool); while (i >= 0) { printf ("Number = %3d\n", i); i = myRandom (-1, &pPool); } printf ("Final = %3d\n", i); return 0; } As you can see from the modified main(), you need to first initialise an int pointer to NULL then pass its address to the myRandom() function. This allows each client (location in the code) to have their own pool which is automatically allocated and freed, although you could still share pools if you wish.
You could use Format-Preserving Encryption to encrypt a counter. Your counter just goes from 0 upwards, and the encryption uses a key of your choice to turn it into a seemingly random value of whatever radix and width you want. Block ciphers normally have a fixed block size of e.g. 64 or 128 bits. But Format-Preserving Encryption allows you to take a standard cipher like AES and make a smaller-width cipher, of whatever radix and width you want (e.g. radix 2, width 16), with an algorithm which is still cryptographically robust. It is guaranteed to never have collisions (because cryptographic algorithms create a 1:1 mapping). It is also reversible (a 2-way mapping), so you can take the resulting number and get back to the counter value you started with. AES-FFX is one proposed standard method to achieve this. I've experimented with some basic Python code which is based on the AES-FFX idea, although not fully conformant--see Python code here. It can e.g. encrypt a counter to a random-looking 7-digit decimal number, or a 16-bit number.
You need to keep track of the numbers you have already used (for instance, in an array). Get a random number, and discard it if it has already been used.
Without relying on external stochastic processes, like radioactive decay or user input, computers will always generate pseudorandom numbers - that is numbers which have many of the statistical properties of random numbers, but repeat in sequences. This explains the suggestions to randomise the computer's output by shuffling. Discarding previously used numbers may lengthen the sequence artificially, but at a cost to the statistics which give the impression of randomness.
The best way to do this is create an array for numbers already used. After a random number has been created then add it to the array. Then when you go to create another random number, ensure that it is not in the array of used numbers.
In addition to using secondary array to store already generated random numbers, invoking random no. seeding function before every call of random no. generation function might help to generate different seq. of random numbers in every run.