<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.extremist.software/index.php?action=history&amp;feed=atom&amp;title=Hack_Notes_CVA_090626</id>
	<title>Hack Notes CVA 090626 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.extremist.software/index.php?action=history&amp;feed=atom&amp;title=Hack_Notes_CVA_090626"/>
	<link rel="alternate" type="text/html" href="https://wiki.extremist.software/index.php?title=Hack_Notes_CVA_090626&amp;action=history"/>
	<updated>2026-04-05T09:12:02Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.13</generator>
	<entry>
		<id>https://wiki.extremist.software/index.php?title=Hack_Notes_CVA_090626&amp;diff=5899&amp;oldid=prev</id>
		<title>SpammerHellDontDelete: New page: I added code to associate the pager motor strength with the activity level, and added fancy crescendoing of the pagers when the turn on and off due to a timing out of the activity level (b...</title>
		<link rel="alternate" type="text/html" href="https://wiki.extremist.software/index.php?title=Hack_Notes_CVA_090626&amp;diff=5899&amp;oldid=prev"/>
		<updated>2009-06-26T23:08:37Z</updated>

		<summary type="html">&lt;p&gt;New page: I added code to associate the pager motor strength with the activity level, and added fancy crescendoing of the pagers when the turn on and off due to a timing out of the activity level (b...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;I added code to associate the pager motor strength with the activity level, and added fancy crescendoing of the pagers when the turn on and off due to a timing out of the activity level (but don&amp;#039;t crescendo when changing between motors of course).&lt;br /&gt;
&lt;br /&gt;
See [[Hack_Notes_CVA_090423]] for an explanation of the timing code.&lt;br /&gt;
&lt;br /&gt;
What I&amp;#039;m doing now is setting a maximum and minimum running motor strength (in the code below it&amp;#039;s 220 and 90 out of 255, respectively). The motor strength then varies within the range in proportion to activity level at any given time. So, if the activity level is 100 out of a maximum possible 200, then the pager motor strength would be 155, 100/200=1/2 and 155 is half-way through the range of 90-220.&lt;br /&gt;
&lt;br /&gt;
Finally, if the counter variable reaches the upper limit as determined by a particular activity level, rather then just turning off instantly, the motor will decrescendo for the current motor strength (calculated as above) down to 50, which is roughly the level at which the motors no longer run at all. Once the strength is at 50, the motor turns of completely (since even if the motor isn&amp;#039;t running it can still consume power). When the counter resets and the motor turns back on, there is a similar crescendo from 50 to the proper motor strength.&lt;br /&gt;
&lt;br /&gt;
If this is unclear, don&amp;#039;t worry. There are lots of magic numbers being moved around...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/* Skory &amp;amp; Eric&lt;br /&gt;
 * Compass Vibro-Anklet&lt;br /&gt;
 * We Rule, June 26, 2009&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* Some code from:&lt;br /&gt;
 * 2009-03-24, pager motor test, lamont lucas&lt;br /&gt;
 */&lt;br /&gt;
/*&lt;br /&gt;
Some Hitachi HM55B Compass reading code copied from: kiilo kiilo@kiilo.org&lt;br /&gt;
License:  http://creativecommons.org/licenses/by-nc-sa/2.5/ch/&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// define the pins used to run the shift registers&lt;br /&gt;
int enable_low = 5;&lt;br /&gt;
int serial_in  = 6;&lt;br /&gt;
int ser_clear_low = 7;&lt;br /&gt;
int RCK  = 11;&lt;br /&gt;
int SRCK = 4;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;math.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
//// define pins used to operate the digital compass (HM55B)&lt;br /&gt;
byte CLK_pin = 10;&lt;br /&gt;
byte EN_pin = 9;&lt;br /&gt;
byte DIO_pin = 8;&lt;br /&gt;
int X_Data = 0;&lt;br /&gt;
int Y_Data = 0;&lt;br /&gt;
int angle;&lt;br /&gt;
int status;&lt;br /&gt;
&lt;br /&gt;
//timing vars&lt;br /&gt;
unsigned long counter = 0;&lt;br /&gt;
int prev_motor = 1;&lt;br /&gt;
int curr_motor = 1;&lt;br /&gt;
int cycles_per_second = 15; //board and compass specific - must measure&lt;br /&gt;
int count;&lt;br /&gt;
int activity = 100;&lt;br /&gt;
int max_activity = 200;&lt;br /&gt;
&lt;br /&gt;
unsigned long serialTimer = millis();&lt;br /&gt;
&lt;br /&gt;
int max_motor_strength = 220;  // 255 = full power&lt;br /&gt;
int min_motor_strength = 90; //point under which motors don&amp;#039;t run or are unfeelable&lt;br /&gt;
int motor_strength = 210; // holds changing motor strength vals&lt;br /&gt;
&lt;br /&gt;
void setup() {&lt;br /&gt;
  pinMode(enable_low, OUTPUT);  // set shift register pins as outputs&lt;br /&gt;
  pinMode(serial_in, OUTPUT);&lt;br /&gt;
  pinMode(ser_clear_low, OUTPUT);&lt;br /&gt;
  pinMode(RCK, OUTPUT);&lt;br /&gt;
  pinMode(SRCK, OUTPUT);&lt;br /&gt;
  &lt;br /&gt;
  // use some serial for debugging&lt;br /&gt;
  Serial.begin(57600);&lt;br /&gt;
  Serial.println(&amp;quot;Setting up board&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  // make sure we start out all off&lt;br /&gt;
  digitalWrite(enable_low, HIGH);&lt;br /&gt;
  // this should wipe out the serial buffer on the shift register&lt;br /&gt;
  digitalWrite(ser_clear_low, LOW);&lt;br /&gt;
  delay(100);   //delay in ms&lt;br /&gt;
  &lt;br /&gt;
  // the TPIC6 clocks work on a rising edge, so make sure they&amp;#039;re low to start.&lt;br /&gt;
  digitalWrite(RCK, LOW);&lt;br /&gt;
  digitalWrite(SRCK, LOW);&lt;br /&gt;
  &lt;br /&gt;
  digitalWrite(ser_clear_low, HIGH);   //we are now clear to write into the serial buffer&lt;br /&gt;
&lt;br /&gt;
  Serial.println(&amp;quot;Board is setup&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  // setup for HM55B compass chip&lt;br /&gt;
  pinMode(EN_pin, OUTPUT);&lt;br /&gt;
  pinMode(CLK_pin, OUTPUT);&lt;br /&gt;
  pinMode(DIO_pin, INPUT);&lt;br /&gt;
&lt;br /&gt;
  HM55B_Reset();&lt;br /&gt;
&lt;br /&gt;
  //set intial motor strength&lt;br /&gt;
  analogWrite(enable_low, 255-max_motor_strength);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
void loop() {&lt;br /&gt;
  // make the compass get a reading&lt;br /&gt;
  &lt;br /&gt;
  HM55B_StartMeasurementCommand(); // necessary!!&lt;br /&gt;
  delay(40); // the data is ready 40ms later&lt;br /&gt;
  status = HM55B_ReadCommand();&lt;br /&gt;
//  Serial.print(status); // read data and print Status&lt;br /&gt;
//  Serial.print(&amp;quot; &amp;quot;);&lt;br /&gt;
  X_Data = ShiftIn(11); // Field strength in X&lt;br /&gt;
  Y_Data = ShiftIn(11); // and Y direction&lt;br /&gt;
  X_Data = X_Data * -1;  // In current rig, chip&lt;br /&gt;
  Y_Data = Y_Data * -1;  // is upside-down; compensate&lt;br /&gt;
  Serial.print(&amp;quot;X: &amp;quot;);&lt;br /&gt;
  Serial.print(X_Data); // print X strength&lt;br /&gt;
  Serial.print(&amp;quot; Y: &amp;quot;);&lt;br /&gt;
  Serial.print(Y_Data); // print Y strength&lt;br /&gt;
  Serial.print(&amp;quot; A: &amp;quot;);&lt;br /&gt;
  digitalWrite(EN_pin, HIGH); // ok deselect chip&lt;br /&gt;
  angle = 180 * (atan2(-1 * Y_Data , X_Data) / M_PI); // angle is atan( -y/x) !!!&lt;br /&gt;
  if (angle &amp;lt; 0) angle = (360 + angle); //offset neg angles&lt;br /&gt;
  Serial.print(angle); // print angle&lt;br /&gt;
  Serial.print(&amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  //Turn on the appropriate motor while keeping track of time and varying motor strength&lt;br /&gt;
  curr_motor = CalcMotor(8, angle);&lt;br /&gt;
  if (curr_motor != prev_motor) { //if we changed angle enough&lt;br /&gt;
    TurnOnMotor(curr_motor);      //turn on the new motor&lt;br /&gt;
    counter = 0;                  //reset counter&lt;br /&gt;
    if (activity &amp;lt; max_activity){&lt;br /&gt;
    activity = activity + 1;      //increase activity level up to 200&lt;br /&gt;
    motor_strength = (((float)activity / (float)max_activity) * (max_motor_strength - min_motor_strength) + min_motor_strength); //set m_strength proportianately to activity&lt;br /&gt;
    }									   // within range of min_ms-max_mas&lt;br /&gt;
  } else {						  //if angle hasn&amp;#039;t changed&lt;br /&gt;
    if (counter &amp;lt; (activity / 10) * cycles_per_second) { //only keep same motor on for&lt;br /&gt;
	analogWrite(enable_low, 255-motor_strength);		 //less than cycles * activity level&lt;br /&gt;
      TurnOnMotor(curr_motor);&lt;br /&gt;
	  while (motor_strength &amp;lt; ((float)activity / (float)max_activity) * (max_motor_strength - min_motor_strength) + min_motor_strength){  	//if m_strength is low (motors off)&lt;br /&gt;
		 motor_strength++;						//crescendo the m_strength&lt;br /&gt;
	     Serial.print(&amp;quot; MS: &amp;quot;);&lt;br /&gt;
		 Serial.println(motor_strength);&lt;br /&gt;
		 analogWrite(enable_low, 255-motor_strength);&lt;br /&gt;
		 delay(50);&lt;br /&gt;
	  }&lt;br /&gt;
    } else {									//if counter runs to upper limit&lt;br /&gt;
	  while (motor_strength &amp;gt; 50){				//if m_strength is high (motors on)&lt;br /&gt;
	     motor_strength--;						//decrescendo the m_strength&lt;br /&gt;
	     analogWrite(enable_low, 255-motor_strength); //50 seems like point motor&lt;br /&gt;
	     Serial.print(&amp;quot; MS: &amp;quot;);					//stops running&lt;br /&gt;
		 Serial.println(motor_strength);&lt;br /&gt;
		 delay(50);&lt;br /&gt;
	  }&lt;br /&gt;
      TurnOnMotor(0);            				//then turn all motors off&lt;br /&gt;
    }&lt;br /&gt;
    counter++;                   //increment counter&lt;br /&gt;
    if (counter &amp;gt; (600 * cycles_per_second) / activity ){&lt;br /&gt;
      counter = 0;               //reset counter&lt;br /&gt;
      if (activity &amp;gt; 13){        //lower activity level&lt;br /&gt;
      activity = activity - 13;  //max val(s) 0-12&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  analogWrite(enable_low, 255-motor_strength);&lt;br /&gt;
  prev_motor = curr_motor;&lt;br /&gt;
&lt;br /&gt;
  Serial.print(&amp;quot;A: &amp;quot;);&lt;br /&gt;
  Serial.print(activity);&lt;br /&gt;
&lt;br /&gt;
  Serial.print(&amp;quot; C: &amp;quot;);&lt;br /&gt;
  Serial.print(counter);&lt;br /&gt;
  &lt;br /&gt;
  Serial.print(&amp;quot; MS: &amp;quot;);&lt;br /&gt;
  Serial.println(motor_strength);&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
//  Serial.print(&amp;quot;counter: &amp;quot;);&lt;br /&gt;
//  Serial.print(counter);&lt;br /&gt;
//  Serial.print(&amp;quot; activity: &amp;quot;);&lt;br /&gt;
//  Serial.println(activity);&lt;br /&gt;
  &lt;br /&gt;
/*&lt;br /&gt;
//Debug wacky motor wiring disorder  &lt;br /&gt;
  count++;&lt;br /&gt;
  TurnOnMotor(count);&lt;br /&gt;
  Serial.print(count); // print angle&lt;br /&gt;
  Serial.println(&amp;quot;  &amp;quot;);&lt;br /&gt;
  delay(2000);&lt;br /&gt;
  if (count &amp;gt;= 8)&lt;br /&gt;
  {&lt;br /&gt;
    count = 0;&lt;br /&gt;
    delay(2000);&lt;br /&gt;
  }&lt;br /&gt;
*/&lt;br /&gt;
  &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//// FUNCTIONS&lt;br /&gt;
&lt;br /&gt;
void TurnOnMotor(int which){&lt;br /&gt;
  // accept which from 1 to 8&lt;br /&gt;
  // send message to shift register as appropiate&lt;br /&gt;
  digitalWrite(enable_low, HIGH);&lt;br /&gt;
  delayMicroseconds(100);  //slow and steady&lt;br /&gt;
//  Serial.print(&amp;quot;Motor  &amp;quot;);&lt;br /&gt;
//  Serial.println(which); // print angle&lt;br /&gt;
  switch(which){&lt;br /&gt;
    case 5:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00000010);&lt;br /&gt;
      break;&lt;br /&gt;
    case 6:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00000001);&lt;br /&gt;
      break;&lt;br /&gt;
    case 7:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00000100);&lt;br /&gt;
      break;&lt;br /&gt;
    case 8:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00001000);&lt;br /&gt;
      break;&lt;br /&gt;
    case 1:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B10000000);&lt;br /&gt;
      break;&lt;br /&gt;
    case 2:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B01000000);&lt;br /&gt;
	  break;&lt;br /&gt;
    case 3:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00100000);&lt;br /&gt;
      break;&lt;br /&gt;
    case 4:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00010000);&lt;br /&gt;
      break;&lt;br /&gt;
    case 9:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B11111111);&lt;br /&gt;
      break;&lt;br /&gt;
    case 10:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B11110000);&lt;br /&gt;
      break;&lt;br /&gt;
    case 11:&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00001111);&lt;br /&gt;
      break;&lt;br /&gt;
    default:&lt;br /&gt;
      // turn them all off&lt;br /&gt;
      shiftOut(serial_in, SRCK, LSBFIRST, B00000000);&lt;br /&gt;
  } &lt;br /&gt;
  //in all cases, pulse RCK to pop that into the outputs&lt;br /&gt;
  delayMicroseconds(100);&lt;br /&gt;
  digitalWrite(RCK, HIGH);&lt;br /&gt;
  delayMicroseconds(100);&lt;br /&gt;
  digitalWrite(RCK, LOW);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int CalcAngle(int howMany, int which)&lt;br /&gt;
{  // function which calculates the &amp;quot;switch to next motor&amp;quot; angle&lt;br /&gt;
  // given how many motors there are in a circle and which position you want&lt;br /&gt;
  // assume which is 1-indexed (i.e. first position is 1, not zero)&lt;br /&gt;
  // assume circle is 0-360, we can always offset later...&lt;br /&gt;
  &lt;br /&gt;
  return (360/howMany*(which-0.5));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int CalcMotor(int howMany, int angle)&lt;br /&gt;
{  // function to calculate which motor to turn on, given&lt;br /&gt;
  // how many motors there are and what the current angle is&lt;br /&gt;
  // assumes motor 1 = angle 0&lt;br /&gt;
  // assumes angle is from 0-360&lt;br /&gt;
  int i;&lt;br /&gt;
  for (i = 1; i&amp;lt;howMany;i++)&lt;br /&gt;
  {&lt;br /&gt;
    if ( (angle &amp;gt;= CalcAngle(howMany, i)) &amp;amp; (angle &amp;lt;= CalcAngle(howMany, i+1)) )&lt;br /&gt;
       return i+1; &lt;br /&gt;
  } &lt;br /&gt;
  // if we&amp;#039;re still here, it&amp;#039;s the last case, the loop over case, which&lt;br /&gt;
  // is actually motor 1 by assumption&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//HM55B Functions&lt;br /&gt;
&lt;br /&gt;
void ShiftOut(int Value, int BitsCount) {&lt;br /&gt;
  for(int i = BitsCount; i &amp;gt;= 0; i--) {&lt;br /&gt;
    digitalWrite(CLK_pin, LOW);&lt;br /&gt;
    if ((Value &amp;amp; 1 &amp;lt;&amp;lt; i) == ( 1 &amp;lt;&amp;lt; i)) {&lt;br /&gt;
      digitalWrite(DIO_pin, HIGH);&lt;br /&gt;
      //Serial.print(&amp;quot;1&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
      digitalWrite(DIO_pin, LOW);&lt;br /&gt;
      //Serial.print(&amp;quot;0&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    digitalWrite(CLK_pin, HIGH);&lt;br /&gt;
    delayMicroseconds(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int ShiftIn(int BitsCount) {&lt;br /&gt;
  int ShiftIn_result;&lt;br /&gt;
    ShiftIn_result = 0;&lt;br /&gt;
    pinMode(DIO_pin, INPUT);&lt;br /&gt;
    for(int i = BitsCount; i &amp;gt;= 0; i--) {&lt;br /&gt;
      digitalWrite(CLK_pin, HIGH);&lt;br /&gt;
      delayMicroseconds(1);&lt;br /&gt;
      if (digitalRead(DIO_pin) == HIGH) {&lt;br /&gt;
        ShiftIn_result = (ShiftIn_result &amp;lt;&amp;lt; 1) + 1; &lt;br /&gt;
      }&lt;br /&gt;
      else {&lt;br /&gt;
        ShiftIn_result = (ShiftIn_result &amp;lt;&amp;lt; 1) + 0;&lt;br /&gt;
      }&lt;br /&gt;
      digitalWrite(CLK_pin, LOW);&lt;br /&gt;
      delayMicroseconds(1);&lt;br /&gt;
    }&lt;br /&gt;
  //Serial.print(&amp;quot;:&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// below is difficult to understand:&lt;br /&gt;
// if bit 11 is Set the value is negative&lt;br /&gt;
// the representation of negative values you&lt;br /&gt;
// have to add B11111000 in the upper Byte of&lt;br /&gt;
// the integer.&lt;br /&gt;
// see: http://en.wikipedia.org/wiki/Two%27s_complement&lt;br /&gt;
  if ((ShiftIn_result &amp;amp; 1 &amp;lt;&amp;lt; 11) == 1 &amp;lt;&amp;lt; 11) {&lt;br /&gt;
    ShiftIn_result = (B11111000 &amp;lt;&amp;lt; 8) | ShiftIn_result; &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  return ShiftIn_result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HM55B_Reset() {&lt;br /&gt;
  pinMode(DIO_pin, OUTPUT);&lt;br /&gt;
  digitalWrite(EN_pin, LOW);&lt;br /&gt;
  ShiftOut(B0000, 3);&lt;br /&gt;
  digitalWrite(EN_pin, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void HM55B_StartMeasurementCommand() {&lt;br /&gt;
  pinMode(DIO_pin, OUTPUT);&lt;br /&gt;
  digitalWrite(EN_pin, LOW);&lt;br /&gt;
  ShiftOut(B1000, 3);&lt;br /&gt;
  digitalWrite(EN_pin, HIGH);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int HM55B_ReadCommand() {&lt;br /&gt;
  int result = 0;&lt;br /&gt;
  pinMode(DIO_pin, OUTPUT);&lt;br /&gt;
  digitalWrite(EN_pin, LOW);&lt;br /&gt;
  ShiftOut(B1100, 3);&lt;br /&gt;
  result = ShiftIn(3);&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Sensebridge]]&lt;/div&gt;</summary>
		<author><name>SpammerHellDontDelete</name></author>
	</entry>
</feed>