As I mentioned elsewhere, the scaled value (which you get when you call SensorValue) is massaged via the code in the function cInputCalcFullScale for several analog sensor types. This is the prototype:
Code: Select all
void cInputCalcFullScale(UWORD *pRawVal, UWORD ZeroPointOffset, UBYTE PctFullScale, UBYTE InvState);
The RCX Light sensor type (SENSOR_TYPE_LIGHT) uses this code:
Code: Select all
cInputCalcFullScale(&InputVal, REFLECTIONSENSORMIN, REFLECTIONSENSORPCTDYN, TRUE);
The NXT light sensor types (SENSOR_TYPE_LIGHT_ACTIVE and SENSOR_TYPE_LIGHT_INACTIVE) uses this code:
Code: Select all
cInputCalcFullScale(&InputVal, NEWLIGHTSENSORMIN, NEWLIGHTSENSORPCTDYN, TRUE);
The NXT sound sensor types (SENSOR_TYPE_SOUND_DB or SENSOR_TYPE_SOUND_DBA) uses this code:
Code: Select all
cInputCalcFullScale(&InputVal, NEWSOUNDSENSORMIN, NEWSOUNDSENSORPCTDYN, TRUE);
The NXT custom sensor type (SENSOR_TYPE_CUSTOM) uses this code:
Code: Select all
cInputCalcFullScale(&InputVal, IOMapInput.Inputs[No].CustomZeroOffset, IOMapInput.Inputs[No].CustomPctFullScale, FALSE);
InputVal is the raw AD value read from the AVR as discussed on the other thread. As you can see there are two important values passed into this function that affect the ScaledValue that comes out in the InputVal variable. Both of these values will be zero by default whenever you power on your NXT. If you say that the full scale percent value is 0 and the zero offset is 0 then the code that executes will have a hard time returning a value other than zero.
Here are the relevant constants for other sensors:
Code: Select all
#define VCC_SENSOR 5000L
#define VCC_SENSOR_DIODE 4300L
#define AD_MAX 1023L
#define REFLECTIONSENSORMIN (1906L/(VCC_SENSOR/AD_MAX))
#define REFLECTIONSENSORMAX ((AD_MAX * 4398L)/VCC_SENSOR)
#define REFLECTIONSENSORPCTDYN (UBYTE)(((REFLECTIONSENSORMAX - REFLECTIONSENSORMIN) * 100L)/AD_MAX)
#define NEWLIGHTSENSORMIN (800L/(VCC_SENSOR/AD_MAX))
#define NEWLIGHTSENSORMAX ((AD_MAX * 4400L)/VCC_SENSOR)
#define NEWLIGHTSENSORPCTDYN (UBYTE)(((NEWLIGHTSENSORMAX - NEWLIGHTSENSORMIN) * 100L)/AD_MAX)
#define NEWSOUNDSENSORMIN (650L/(VCC_SENSOR/AD_MAX))
#define NEWSOUNDSENSORMAX ((AD_MAX * 4980L)/VCC_SENSOR)
#define NEWSOUNDSENSORPCTDYN (UBYTE)(((NEWSOUNDSENSORMAX - NEWSOUNDSENSORMIN) * 100L)/AD_MAX)
#define SENSOR_RESOLUTION 1023L
And the cInputCalcFullScale function:
Code: Select all
void cInputCalcFullScale(UWORD *pRawVal, UWORD ZeroPointOffset, UBYTE PctFullScale, UBYTE InvStatus)
{
if (*pRawVal >= ZeroPointOffset)
{
*pRawVal -= ZeroPointOffset;
}
else
{
*pRawVal = 0;
}
*pRawVal = (*pRawVal * 100)/PctFullScale;
if (*pRawVal > SENSOR_RESOLUTION)
{
*pRawVal = SENSOR_RESOLUTION;
}
if (TRUE == InvStatus)
{
*pRawVal = SENSOR_RESOLUTION - *pRawVal;
}
}
In fact, you really should get a divide by zero error but it seems like the IAR compiler is returning 0 when you divide by zero.
Here's an NXC program that you can use to explore the affect of adjusting the custom sensor required values:
Code: Select all
#define VCC_SENSOR 5000
#define VCC_SENSOR_DIODE 4300
#define AD_MAX 1023
/*
#define REFLECTIONSENSORMIN 389
#define REFLECTIONSENSORMAX 899
#define REFLECTIONSENSORPCTDYN 49
#define NEWLIGHTSENSORMIN 163
#define NEWLIGHTSENSORMAX 900
#define NEWLIGHTSENSORPCTDYN 72
#define NEWSOUNDSENSORMIN 132
#define NEWSOUNDSENSORMAX 1018
#define NEWSOUNDSENSORPCTDYN 86
*/
#define REFLECTIONSENSORMIN (1906/(VCC_SENSOR/AD_MAX))
#define REFLECTIONSENSORMAX ((AD_MAX*4398)/VCC_SENSOR)
#define REFLECTIONSENSORPCTDYN (((REFLECTIONSENSORMAX-REFLECTIONSENSORMIN)*100)/AD_MAX)
#define NEWLIGHTSENSORMIN (800/(VCC_SENSOR/AD_MAX))
#define NEWLIGHTSENSORMAX ((AD_MAX*4400)/VCC_SENSOR)
#define NEWLIGHTSENSORPCTDYN (((NEWLIGHTSENSORMAX-NEWLIGHTSENSORMIN)*100)/AD_MAX)
#define NEWSOUNDSENSORMIN (650/(VCC_SENSOR/AD_MAX))
#define NEWSOUNDSENSORMAX ((AD_MAX*4980)/VCC_SENSOR)
#define NEWSOUNDSENSORPCTDYN (((NEWSOUNDSENSORMAX-NEWSOUNDSENSORMIN)*100)/AD_MAX)
#define SENSOR_RESOLUTION 1023
task main()
{
int zeroOffset = 0;
byte pctFullScale = 200;
SetSensorType(S1, SENSOR_TYPE_CUSTOM);
SetSensorMode(S1, SENSOR_MODE_RAW);
// SetCustomSensorZeroOffset currently requires a word-sized variable
// unless you pass in a value that cannot fit within a byte (i.e.,
// something greater than 255)
SetCustomSensorZeroOffset(S1, zeroOffset);
// SetCustomSensorZeroOffset(S1, 256); // this would compile
// SetCustomSensorZeroOffset(S1, 0); // this would not compile
SetCustomSensorActiveStatus(S1, INPUT_CUSTOMINACTIVE);
SetCustomSensorPercentFullScale(S1, pctFullScale);
ResetSensor(S1);
NumOut(0, LCD_LINE1, SensorValue(S1));
NumOut(0, LCD_LINE2, SensorRaw(S1));
NumOut(0, LCD_LINE3, SensorNormalized(S1));
NumOut(0, LCD_LINE4, REFLECTIONSENSORMIN);
NumOut(0, LCD_LINE5, REFLECTIONSENSORPCTDYN);
NumOut(0, LCD_LINE6, NEWLIGHTSENSORMIN);
NumOut(0, LCD_LINE7, NEWLIGHTSENSORPCTDYN);
while(true);
}
In any case, the custom sensor type is working just as it was designed to work. You just didn't know that you had to set some additional values if you want to use the custom sensor type. The documentation will be updated to do a better job of explaining how to use a custom digital or analog custom sensor with your NXT.
John Hansen