Well that was fun.
Today we had no lecture, instead the entire day was devoted to a team project. Specifically we designed and implemented the software for a scuba diving computer. Something that would look like this.
 
Our hardware actually looked like this, but the functionality was much the same.
 
We worked in teams of 4 to develop the software required to do the following.
1 - Show ascent-rate, depth, oxygen remaining, elapsed dive time and time to surface on the display.
2 - Sound one of three alarms.
- High priority alarm if there is not enough oxygen in the tanks to reach the surface.
- Medium priority alarm if the rate of ascent is greater than 15 meters per minute (prevents getting the bends).
- Low priority alarm if your depth is greater than 40 meters.
3 – Toggle the display between showing the elapsed time, and the time to surface every 2 seconds.
This is why I love being an engineer; you get to build really cool things. As an aside our team was the only one to finish the project. We finished it 5 minutes before the deadline. Whew…
To complete the project our design used 8 tasks.
- LED driver task
- Pushbutton driver task
- Speaker driver task
- Analog to digital converter driver task
- Calculation task
- Display task
- Alarm task
- Watchdog monitoring task
As a point of interest I have included below some of the code that I worked on today which did the calculations for the displayed values. Probably not the most elegant code since we were under a time constraint, but it shows the proper use of several forms of inter-task communication. Enjoy.
/***********************************************************
DIVE COMPUTER CALCULATION TASK
***********************************************************/
void AppTaskCalc(void * pdata)
{
   INT16S         rate_of_ascent_in_mpm = 0;
   INT16U         elapsed_time_in_s = 0;
   INT32S         depth_in_mm = 0;
   INT32S         air_supply_in_cl = 0;
   OS_FLAGS       flags;
   INT8U          err;
   INT16U         sample;
   INT16U         tick_counter = 0;
   INT16U         air_to_surface_in_cl;
   INT32U         alarm_curr = GF_ALARM_OFF;
   INT8U          at_surface = 1;
   static display_data_t display_data = {0,0,0,0,0};  
   while(1)
   {
      flags = OSFlagPend(gh_sys_flags, GF_TIME_CALC | 
              GF_BUTTON_AIR, OS_FLAG_WAIT_SET_ANY | 
              OS_FLAG_CONSUME, 0, &err);
      assert(OS_NO_ERR == err);    
      
      if (flags & GF_TIME_CALC)
      {
         tick_counter++;
         // Pend on the A2D mailbox
         sample = (*(INT16U *) OSMboxPend(ghMboxAdc, 
                                          10, &err));
         assert(OS_NO_ERR == err || OS_TIMEOUT == err);
         
         // Calculate the rate of ascent
         rate_of_ascent_in_mpm = sample - 511;
         rate_of_ascent_in_mpm /= 13;
         depth_in_mm -= depth_change_in_mm(
                                  rate_of_ascent_in_mpm);
         if(depth_in_mm <= 0)
         {
            depth_in_mm = 0;
            at_surface = 1;
         }  
         // Calculate the elapsed time if depth is not 0
         if (depth_in_mm != 0)
         {
            if (at_surface == 1)
            {
               at_surface = 0;
               elapsed_time_in_s = 0;
            }
            if(tick_counter & 0x01)
            {
               // Every other .5s tick increment
               //   the elapsed time
               elapsed_time_in_s++;
            }
         }
         if(at_surface == 0)
         {
            air_supply_in_cl -= gas_rate_in_cl( 
                                   depth_in_mm / 1000);
            if(air_supply_in_cl < 0)
            {
               air_supply_in_cl = 0;
            }
         }
         air_to_surface_in_cl = gas_to_surface_in_l( 
                                   depth_in_mm / 1000);
         // Update display_data struct
         if(at_surface == 1)
         {
            display_data.rate_of_ascent_in_mpm = 0;
         }
         else
         {
            display_data.rate_of_ascent_in_mpm = 
                                      rate_of_ascent_in_mpm;
         }
         display_data.depth_in_m = depth_in_mm / 1000;
         display_data.air_supply_in_cl = air_supply_in_cl;
         display_data.elapsed_time_in_s = elapsed_time_in_s;
         
         // Maximum ascent rate is 0.25m / s
         display_data.time_to_surface_in_s =
                          display_data.depth_in_m * 4;
         err = OSMboxPost(ghMboxCalc, &display_data);
         assert(OS_NO_ERR == err);
         
         OSFlagPost(gh_sys_flags, GF_MBOX_DISP, 
                                        OS_FLAG_SET, &err);
         assert(OS_NO_ERR == err);
         
         // Set current alarm state.
         if(at_surface == 1)
         {
            alarm_curr = GF_ALARM_OFF;
         }
         else if (air_supply_in_cl < air_to_surface_in_cl)
         {
            alarm_curr = GF_ALARM_HI;
         }
         else if (15 < rate_of_ascent_in_mpm)
         {
            alarm_curr = GF_ALARM_MID;
         }
         else if (40 < (depth_in_mm / 1000))
         {
            alarm_curr = GF_ALARM_LOW;
         }
         else
         {
            alarm_curr = GF_ALARM_OFF;
         }  
         // Signal change of speaker priority to the alarm
         OSFlagPost(gh_sys_flags, alarm_curr, 
                                      OS_FLAG_SET, &err);
         assert(OS_NO_ERR == err);
      }
      
      if (flags & GF_BUTTON_AIR)
      {
         // Increment the air count at 5L per semaphore
         do 
         {
            // Wait for a signal from the button driver
            OSSemPend(ghSemB1, 10, &err); 
            assert(OS_NO_ERR == err || OS_TIMEOUT == err);
            if ((OS_NO_ERR == err) && (at_surface == 1))
            {
               if (air_supply_in_cl <= 199500)
               {
                  air_supply_in_cl += 500;
               }
               else if (air_supply_in_cl < 200000)
               {
                  air_supply_in_cl = 200000;
               }
            }
         }while (OS_NO_ERR == err);
      }
      // tell watchdog we are alive
      OSFlagPost(gh_sys_flags, GF_ALIVE_CALC, 
                                       OS_FLAG_SET, &err);
      assert(OS_NO_ERR == err);      
   }
}
 
 
No comments:
Post a Comment