Advertisement
Guest User

Untitled

a guest
Mar 21st, 2019
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.92 KB | None | 0 0
  1.  
  2. // v1.2 -adjusted numsteps for proper door opening
  3. // v2.0 -removed ultrasound sensor and added second IR motion detector
  4. // V3.0 -Simplified I/O, replaced ext interrupt with internal timer0 compare interrupt.
  5. // -Added Oled display
  6. // -Cleaned up the code. Created functions for some tasks.
  7. // -Added ir remote.
  8. // V3.1-Added graphic UI instead of text
  9. // V3.2-Added screen saver
  10. // V3.3-Added 10ms break period
  11. // -Added variable speed. Ended up slowing the top speed, the motor was skipping steps.
  12. // -Animated the door display
  13.  
  14.  
  15. #include <Adafruit_SSD1306.h>
  16.  
  17. //oled uses I2C pins A5 SCL and A4 SDA. A reset pin must be declared in the display declaration
  18. //if the I2C device does not need reset, pin SDA can be used in the display declaration
  19. #define OLED_RESET A4
  20. Adafruit_SSD1306 display(OLED_RESET);
  21.  
  22. #if (SSD1306_LCDHEIGHT != 64)
  23. #error("Height incorrect, please fix Adafruit_SSD1306.h!");
  24. #endif
  25.  
  26.  
  27.  
  28.  
  29.  
  30. // Stepper definitions
  31. #define BLU 8 //definition digital 8 pins as pin to control the IN1 (ULN2003)
  32. #define PNK 9 //definition digital 9 pins as pin to control the IN2 (ULN2003)
  33. #define YEL 10 //definition digital 10 pins as pin to control the IN3 (ULN2003)
  34. #define ORG 11 //definition digital 11 pins as pin to control the IN4 (ULN2003)
  35.  
  36. volatile byte stepper_control = false; //command/status reg for the stepper interrupt routine.
  37. // bit 0 = true = run/running
  38. // bit 1 = direction = 1 clockwise, 0 counterclockwise
  39. byte clockwise = true; //general flag for motor direction for opening.
  40. volatile int step_counter = 0; // number of steps to execute, steps left on read
  41. volatile byte micro_step = 0; //keeps track of the stepper interupt routine state
  42. #define FAST 1; // full speed would be 0 but the motor can't keep up
  43. #define MEDIUMFAST 1;
  44. #define MEDIUM 2;
  45. #define SLOW 3;
  46. volatile byte motor_speed = SLOW; //tells the motor interrupt routine how many ticks to skip. 0 is Fast,
  47.  
  48.  
  49. // Control panels LED definitions
  50. //digital pin LED_BUILTIN as an output to display motion detection status (13)
  51.  
  52. // IR motion detection definitions
  53. #define PIRpin1 7 // IR motion detector input pin
  54. #define PIRpin2 6 // second IR sensor input pin
  55.  
  56. // Control panels Push button
  57. #define DOOR_MANUAL_PIN 5
  58. #define CLOSE_BUTTON_PIN 4
  59. #define OPEN_BUTTON_PIN 3
  60.  
  61.  
  62. // miscaleneous program variables and constants
  63.  
  64. byte manual_flag = false; // when true, inhibits automatic operations
  65. volatile byte ir_new_status = false;
  66.  
  67. // Interrupt-based timers. When enabled, count down to zero and clear the enable bit when count = 0.
  68. // Counters are decremented before checking for zero, so they can start at 0 for a full 16 bit count.
  69. volatile int timer0 = 0; //door open timer
  70. volatile int timer1 = 0; //sensor scan timer
  71.  
  72. int blank_screen_timer = 0; //screen saver timer. THIS TIMER IS NOT DECREMENTED IN THE INTERRUPT ROUTINE.
  73. // IT IS DECREMENTED IN THE SENSOR TESTING SECTION OF THE MAIN LOOP @5HZ.
  74. volatile byte timers_status = 0; //Each bit is a control/status flag for a counter. 1= start/running, 0 = stopped/done
  75.  
  76.  
  77. #define NUM_STEPS 1450 // number of steps before reversing direction
  78. #define OPEN_DELAY 5000 // 5 seconds. Minimum time door held open
  79. #define SENSOR_SCAN_DELAY 200 // .2 second between sensor scans
  80. #define DISPLAY_DELAY 3000 //
  81. #define SCREENSAVE_DELAY 300 // 300 * .2 secs = 60 secs.
  82.  
  83. #define CLOSED 0
  84. #define OPENING 1
  85. #define OPENED 2
  86. #define CLOSING 3
  87. byte door_state = CLOSED;
  88.  
  89. // Register bit masks
  90. #define BIT0 1
  91. #define BIT1 2
  92. #define BIT2 4
  93. #define BIT3 8
  94. #define BIT4 16
  95. #define BIT5 32
  96. #define BIT6 64
  97. #define BIT7 128
  98.  
  99. //ir receiver
  100. #include <IRremote.h>
  101.  
  102. int RECV_PIN = 2;//The definition of the infrared receiver pin 2
  103. IRrecv irrecv(RECV_PIN);
  104. decode_results results;
  105.  
  106. byte ir_code; // holds the least significant byte of the received ir code
  107.  
  108.  
  109.  
  110.  
  111. void PrintDisplay(String text)
  112. {
  113. display.setTextSize(2);
  114. display.clearDisplay();
  115. display.setCursor(0, 0); // set the cursor to column 0, line 0
  116. display.print(text);
  117. display.display();
  118.  
  119. }
  120.  
  121. void DisplayStatus(void)
  122. {
  123.  
  124. int door_pos;
  125.  
  126. noInterrupts();
  127. door_pos = step_counter;
  128. interrupts();
  129.  
  130. display.clearDisplay();
  131. display.setCursor(0, 0); // set the cursor to column 0, line 0
  132. switch(door_state)
  133. {
  134. case CLOSED:
  135. display.drawRect(50, 0, 40, 64, 1);
  136. display.fillRect(50, 0, 40, 64, 1);
  137. break;
  138.  
  139. case OPENING:
  140. display.fillTriangle(5, 0, 5, 16, 21, 8, WHITE);
  141. display.fillTriangle(21, 0, 21, 16, 37, 8, WHITE);
  142. display.fillRect(37, 0, 2, 16, WHITE);
  143. display.drawRect(50, 0, 40, 64, WHITE);
  144.  
  145. if(door_pos > (NUM_STEPS - 100))
  146. {
  147. display.fillRect(60, 0, 30, 64, WHITE);
  148. }else if(door_pos > (NUM_STEPS - 300))
  149. {
  150. display.fillRect(65, 0, 25, 64, WHITE);
  151. }else if(door_pos > (NUM_STEPS - 600))
  152. {
  153. display.fillRect(70, 0, 20, 64, WHITE);
  154. }else if(door_pos > (NUM_STEPS - 900))
  155. {
  156. display.fillRect(75, 0, 15, 64, WHITE);
  157. }else if(door_pos > (NUM_STEPS - 1200))
  158. {
  159. display.fillRect(80, 0, 10, 64, WHITE);
  160. }else
  161. {
  162. display.fillRect(83, 0, 7, 64, WHITE);
  163. }
  164.  
  165. break;
  166.  
  167. case OPENED:
  168. display.drawRect(50, 0, 40, 64, WHITE);
  169. display.fillRect(86, 0, 4, 64, WHITE);
  170. break;
  171.  
  172. case CLOSING:
  173. display.fillRect(5, 0, 2, 16, WHITE);
  174. display.fillTriangle(7, 8, 23, 16, 23, 0, WHITE);
  175. display.fillTriangle(23, 8, 39, 16, 39, 0, WHITE);
  176. display.drawRect(50, 0, 40, 64, WHITE);
  177. if(door_pos > (NUM_STEPS - 100))
  178. {
  179. display.fillRect(83, 0, 7, 64, WHITE);
  180. }else if(door_pos > (NUM_STEPS - 300))
  181. {
  182. display.fillRect(80, 0, 10, 64, WHITE);
  183. }else if(door_pos > (NUM_STEPS - 600))
  184. {
  185. display.fillRect(75, 0, 15, 64, WHITE);
  186. }else if(door_pos > (NUM_STEPS - 900))
  187. {
  188. display.fillRect(70, 0, 20, 64, WHITE);
  189. }else if(door_pos > (NUM_STEPS - 1200))
  190. {
  191. display.fillRect(65, 0, 25, 64, WHITE);
  192. }else
  193. {
  194. display.fillRect(60, 0, 30, 64, WHITE);
  195. }
  196.  
  197. break;
  198.  
  199. }
  200.  
  201. if(digitalRead(PIRpin1))
  202. {
  203. display.fillCircle(25, 32, 5, WHITE);
  204. }else
  205. {
  206. display.drawCircle(25, 32, 5, WHITE);
  207.  
  208. }
  209.  
  210. if(digitalRead(PIRpin2))
  211. {
  212. display.fillCircle(115, 32, 5, WHITE);
  213. }else
  214. {
  215. display.drawCircle(115, 32, 5, WHITE);
  216.  
  217. }
  218.  
  219.  
  220. if (!manual_flag)
  221. {
  222. display.fillTriangle(5, 47, 5, 63, 21, 55, WHITE);
  223. }
  224. else
  225. {
  226. display.fillRect(5, 47, 16, 16, WHITE);
  227.  
  228. }
  229. display.display();
  230.  
  231. }
  232.  
  233. int MotorStopped(void) //checks if motor is stopped. returns true if it is stopped.
  234. {
  235. if(!bitRead(stepper_control,BIT0) && (micro_step == 0)) //if motor is stopped
  236. {
  237. return true;
  238. }
  239. else
  240. {
  241. return false;
  242. }
  243. }
  244.  
  245. void MotorStart(int numsteps, int dir)
  246. {
  247. motor_speed = SLOW;
  248. step_counter = numsteps;
  249. bitWrite(stepper_control,BIT1, dir);
  250. bitSet(stepper_control,BIT0);
  251.  
  252. }
  253.  
  254.  
  255. void MotorOff(void)
  256. {
  257. delay(10); //delay 10ms to allow motor to brake
  258. PORTB = PORTB & B11110000; //shut off the door motors to reduce power consumption
  259.  
  260. }
  261.  
  262.  
  263.  
  264. void setup()
  265. {
  266. // setup display
  267. // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  268. display.begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS); // initialize with the I2C addr 0x3C (for the 128x64)
  269. display.setTextColor(WHITE);
  270. display.setTextSize(2);
  271. display.display();
  272. delay(DISPLAY_DELAY);
  273.  
  274. PrintDisplay("Starting");
  275.  
  276. // setup stepper outputs
  277. MotorOff(); //make sure that the port is cleared before turning on the outputs
  278. pinMode(ORG, OUTPUT);
  279. pinMode(YEL, OUTPUT);
  280. pinMode(PNK, OUTPUT);
  281. pinMode(BLU, OUTPUT);
  282. MotorOff(); //just in case...
  283.  
  284. clockwise = true; //initial opening direction
  285. micro_step = 0; //set up the state machine to start at micro_step 0
  286. bitClear(stepper_control,BIT0);
  287. bitWrite(stepper_control,BIT1,clockwise);
  288. motor_speed = SLOW;
  289. step_counter = NUM_STEPS;
  290. door_state = CLOSED;
  291. manual_flag = true; //start in manual mode for a controlled startup and no door opening until everything is ready.
  292.  
  293.  
  294.  
  295. //Init the push-buttons, LEDs and door switch inputs
  296. pinMode(CLOSE_BUTTON_PIN, INPUT_PULLUP);
  297. pinMode(OPEN_BUTTON_PIN, INPUT_PULLUP);
  298. pinMode(DOOR_MANUAL_PIN, INPUT_PULLUP);
  299.  
  300.  
  301. // initialize digital pin LED_BUILTIN as an output to display motion detection status (pin 13)
  302. pinMode(LED_BUILTIN, OUTPUT);
  303. digitalWrite(LED_BUILTIN,LOW);
  304.  
  305. // init the IR sensor inputs
  306. pinMode(PIRpin1, INPUT_PULLUP);
  307. pinMode(PIRpin2, INPUT_PULLUP);
  308. ir_new_status = false;
  309.  
  310. // enable the ir receiver
  311. irrecv.enableIRIn(); // Initialization infrared receiver
  312.  
  313.  
  314. //Init the sofware timers
  315. timers_status = 0;
  316. timer0 = 0; //door open timer
  317. // set the sensor scan timer
  318. timer1 = SENSOR_SCAN_DELAY;
  319. blank_screen_timer = SCREENSAVE_DELAY;
  320. bitSet(timers_status, BIT1); //start timer1, sensor timer.
  321.  
  322.  
  323. //Start the comparator (rtc) interrupts
  324. // Hardware Timer0 is already used for millis() - we'll just interrupt at 0
  325. // and process the interrupt in the comparator SIGNAL interrupt routine.
  326.  
  327. OCR0A = 0x00;
  328. TIMSK0 |= _BV(OCIE0A); //enable comparator interrupts
  329. }
  330.  
  331. void loop()
  332. {
  333. //start with handling the door state machine
  334.  
  335. switch (door_state)
  336. {
  337. case CLOSED:
  338.  
  339. if(ir_new_status)
  340. {
  341. if(MotorStopped()) //if motor is stopped
  342. {
  343. clockwise = true; //set the direction
  344. MotorStart(NUM_STEPS, clockwise);
  345. door_state = OPENING;
  346. }
  347. }else if (MotorStopped()) //if motor is stopped but no sensors active
  348. {
  349. if(digitalRead(OPEN_BUTTON_PIN) == LOW)
  350. {
  351. MotorStart(1, true);
  352. }else if(digitalRead(CLOSE_BUTTON_PIN) == LOW)
  353. {
  354. MotorStart(1, false);
  355. }else
  356. {
  357. MotorOff();
  358. }
  359.  
  360. }
  361. break;
  362.  
  363. case OPENING:
  364.  
  365. // wait for the motor to stop
  366. if(MotorStopped()) //if motor is stopped
  367. {
  368. MotorOff();
  369. // set the timer
  370. bitClear(timers_status,BIT0);
  371. delay(2); // need this delay to allow interrupt to occur. not sure why. intermittent when no delay
  372. timer0 = OPEN_DELAY;
  373. bitSet(timers_status, BIT0);
  374. door_state = OPENED;
  375. }
  376.  
  377. break;
  378.  
  379. case OPENED:
  380.  
  381. // if we get motion, restart the timer
  382. if(ir_new_status)
  383. {
  384. // reset the timer
  385. bitClear(timers_status,BIT0);
  386. delay(2); // need this delay to allow interrupt to occur. not sure why. intermittent when no delay
  387. timer0 = OPEN_DELAY;
  388. bitSet(timers_status, BIT0);
  389.  
  390. }else if (!bitRead(timers_status, BIT0)) // no motion detected, wait for timer to time out
  391. {
  392. // timer timed out, reverse direction and start motor
  393. clockwise = false; //set the direction
  394. MotorStart(NUM_STEPS, clockwise);
  395. door_state = CLOSING;
  396. }
  397. break;
  398.  
  399. case CLOSING:
  400.  
  401. if(ir_new_status)
  402. {
  403. bitClear(stepper_control, BIT0); //stop the motor
  404. while (!MotorStopped()) //wait for motor to stop
  405. {
  406. delay(1); //waste time.
  407. }
  408. {
  409. clockwise = true; //flip the direction
  410. MotorStart((NUM_STEPS - step_counter), clockwise);
  411. door_state = OPENING;
  412. }
  413. }else if(MotorStopped()) //if motor is stopped
  414.  
  415. {
  416. MotorOff();
  417.  
  418. door_state = CLOSED;
  419.  
  420. }
  421.  
  422. break;
  423. }// end switch case for motor control
  424.  
  425. //done with the door, do the sensors
  426.  
  427. if (!bitRead(timers_status, BIT1))//Timer timed out, do a scan of inputs
  428. {
  429. if(manual_flag == false)
  430. {
  431. // check IR for motion
  432. ir_new_status = digitalRead(PIRpin1) || digitalRead(PIRpin2);
  433. digitalWrite(LED_BUILTIN,ir_new_status); //set to automatic, display the sensor status
  434. }else
  435. {
  436. digitalWrite(LED_BUILTIN,manual_flag); //set to manual, turn on the LED
  437. }
  438.  
  439. // detect change of state in manual/auto button
  440.  
  441. if(!digitalRead(DOOR_MANUAL_PIN)) //look for high to low transition
  442. {
  443. manual_flag = !manual_flag; //flip operation mode
  444. delay(200); //debounce
  445. blank_screen_timer = SCREENSAVE_DELAY; //reset the screen saver timer
  446. }
  447.  
  448. // check for received ir commands
  449. if (irrecv.decode(&results))
  450. {
  451. ir_code = results.value & 0xFF;
  452. if (ir_code == 0xBB)
  453. {
  454. manual_flag = !manual_flag; //flip operation mode
  455.  
  456. } else if ((ir_code == 0x1B) && manual_flag) //manual open by faking movement detection
  457. {
  458. ir_new_status = true;
  459. }else if ((ir_code == 0x1F) && manual_flag && (door_state == OPENED)) //manual close by faking moment detection
  460. {
  461. ir_new_status = false; // no movement
  462. bitClear(timers_status,BIT0); // force open delay timer timeout
  463.  
  464. }else if ((ir_code == 0xDB) && manual_flag && (door_state == CLOSED))
  465. {
  466. MotorStart(10, true); //open the door by 10 step
  467. }else if ((ir_code == 0x3B) && manual_flag && (door_state == CLOSED))
  468. {
  469. MotorStart(10, false); //close the door by 10 step
  470. }
  471. irrecv.resume(); //Receiving the next value
  472. blank_screen_timer = SCREENSAVE_DELAY; // reset the screen saver timer
  473. }
  474.  
  475. if(blank_screen_timer != 0) // screen saver timer not timed out, so display the status
  476. {
  477. DisplayStatus();
  478. --blank_screen_timer; //decrement timer
  479.  
  480. }else
  481. {
  482. display.clearDisplay(); // call the screen saver.
  483. display.display();
  484. }
  485.  
  486.  
  487.  
  488. // reset the sensor scan timer
  489. timer1 = SENSOR_SCAN_DELAY; //reset the sensor scan timer
  490. bitSet(timers_status, BIT1); //restart it
  491.  
  492. }// end sensor processing
  493.  
  494. }//end main loop
  495.  
  496.  
  497.  
  498.  
  499. // Interrupt is called once a millisecond,
  500. SIGNAL(TIMER0_COMPA_vect) {
  501.  
  502.  
  503. // stepper motor controler
  504.  
  505. if (motor_speed == 0) //if the speed counter has reached 0, go process the motor
  506. {
  507. if(!MotorStopped())
  508. {
  509. if((step_counter != 0) || (micro_step != 0)) {
  510. MicroStep();
  511. }else
  512. {
  513. bitClear(stepper_control,BIT0); //we're done with the rotation, signal main loop by clearing the control reg.
  514. }
  515. }
  516. //done with the motor, now find out what to reload the motor speed counter with
  517. if(step_counter > (NUM_STEPS - 50) || (step_counter <= 50))
  518. {
  519. motor_speed = SLOW;
  520. }else if (step_counter > (NUM_STEPS - 100) || (step_counter <= 100))
  521. {
  522. motor_speed = MEDIUM;
  523. }else if (step_counter > (NUM_STEPS - 150) || (step_counter <= 150))
  524. {
  525. motor_speed = MEDIUMFAST;
  526. }else
  527. {
  528. motor_speed = FAST;
  529. }
  530.  
  531.  
  532. }else //,just decrement the motor speed counter
  533. {
  534. --motor_speed;
  535. }
  536.  
  537.  
  538.  
  539. // Timers
  540. if(bitRead(timers_status, BIT0))
  541. {
  542. --timer0;
  543. if(timer0 == 0){
  544. bitClear(timers_status, BIT0); //bit clear the timer status bit.
  545. }
  546. }
  547.  
  548. if(bitRead(timers_status, BIT1))
  549. {
  550. --timer1;
  551. if(timer1 == 0){
  552. bitClear(timers_status, BIT1); //bit clear the timer status bit.
  553. }
  554. }
  555.  
  556.  
  557.  
  558. }
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565. void MicroStep()//Stepper motor rotation 1 step
  566. {
  567. // Serial.println(step_counter);
  568. if (bitRead(stepper_control,BIT1))
  569. { // Stepper motor clockwise
  570. switch (micro_step)
  571. {
  572. case 0:
  573. // org yel pink blue
  574. PORTB = (PORTB & B11110000) | B00000001; //read upper nibble to restore state in case they are being used
  575. break;
  576. case 1:
  577. PORTB = (PORTB & B11110000) | B00000011;
  578. break;
  579. case 2:
  580. PORTB = (PORTB & B11110000) | B00000010;
  581. break;
  582. case 3:
  583. PORTB = (PORTB & B11110000) | B00000110;
  584. break;
  585. case 4:
  586. PORTB = (PORTB & B11110000) | B00000100;
  587. break;
  588. case 5:
  589. PORTB = (PORTB & B11110000) | B00001100;
  590. break;
  591. case 6:
  592. PORTB = (PORTB & B11110000) | B00001000;
  593. break;
  594. case 7:
  595. PORTB = (PORTB & B11110000) | B00001001;
  596. step_counter = --step_counter;
  597. break;
  598. }
  599. micro_step = ++micro_step & 0x0007;
  600. } else
  601. { // Stepper counter-clockwise
  602. // org yel pnk blu
  603. switch (micro_step)
  604. {
  605. case 0:
  606. PORTB = (PORTB & B11110000) | B00001001;
  607. break;
  608. case 1:
  609. PORTB = (PORTB & B11110000) | B00001000;
  610. break;
  611. case 2:
  612. PORTB = (PORTB & B11110000) | B00001100;
  613. break;
  614. case 3:
  615. PORTB = (PORTB & B11110000) | B00000100;
  616. break;
  617. case 4:
  618. PORTB = (PORTB & B11110000) | B00000110;
  619. break;
  620. case 5:
  621. PORTB = (PORTB & B11110000) | B00000010;
  622. break;
  623. case 6:
  624. PORTB = (PORTB & B11110000) | B00000011;
  625. break;
  626. case 7:
  627. PORTB = (PORTB & B11110000) | B00000001;
  628. step_counter = --step_counter;
  629. break;
  630. }
  631. micro_step = ++micro_step & 0x0007;
  632. }
  633. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement