{"id":21373,"date":"2017-04-02T01:00:20","date_gmt":"2017-04-02T11:00:20","guid":{"rendered":"http:\/\/darkerview.com\/wordpress\/?p=21373"},"modified":"2017-04-02T11:35:34","modified_gmt":"2017-04-02T21:35:34","slug":"bang-bang","status":"publish","type":"post","link":"https:\/\/darkerview.com\/wordpress\/?p=21373","title":{"rendered":"Bang-Bang"},"content":{"rendered":"<p>I took a break from working with a &#8220;big&#8221; microcontroller to work with a little one.  The <a href=\"http:\/\/www.microchip.com\/wwwproducts\/en\/en010106\" target=\"_blank\">PIC12C671<\/a> is definitely little when compared with the PIC18F66K80 I am using in the <a href=\"https:\/\/darkerview.com\/wordpress\/?p=20337\">GenPIC utility PCB<\/a>.  With less than 2k of program space and a mere 128 bytes of RAM it is definitely limited.  Consider that the chip only has eight pins, two of which are power and ground, leaving six I\/O pins to get the job done.  No problem, I only need two I\/O pins for this task and that few bytes of RAM is more than enough!<\/p>\n<p><figure id=\"attachment_21390\" aria-describedby=\"caption-attachment-21390\" style=\"width: 200px\" class=\"wp-caption alignright\"><a href=\"https:\/\/darkerview.com\/wordpress\/?attachment_id=21390\" rel=\"attachment wp-att-21390\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/darkerview.com\/wordpress\/wp-content\/uploads\/2017\/03\/BangBangHeater-200x200.jpg\" alt=\"A simple heater using a bang-bang controller.\" width=\"200\" height=\"200\" class=\"size-thumbnail wp-image-21390\" \/><\/a><figcaption id=\"caption-attachment-21390\" class=\"wp-caption-text\">A simple heater using a bang-bang controller.<\/figcaption><\/figure>This project is pretty basic&#8230;  A bang-bang heater controller.  This simple form of controller simply turns on and off as the temperature (or some other controlled parameter) goes up and down, there is no attempt to vary the output, all or nothing. Bang on, bang off, or simply a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bang%E2%80%93bang_control\" target=\"_blank\">bang-bang controller<\/a> as it is known in the trade.<\/p>\n<p>A bang-bang controller is inherently reliable and stable because it uses two different control setpoints, a high and a low.  Because these control points are separated by a large margin, called hysteresis, the controller will not oscillate or rapidly turn on and off.  In this case the heater will not turn on until the temperature falls below 10&deg;C and will not turn back off until the temperature rises above 15&deg;C.  That five degree margin is called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hysteresis\" target=\"_blank\">hysteresis<\/a>, and ensures a good period of time between on and off.<\/p>\n<p><!--more-->Shown in the chart here is the actual performance of this heater in a test.  OK, this test is just the heater, placed in a small cardboard box, which in turn was placed in a refrigerator.  All the better as this particular refrigerator was the break-room fridge at Keck Observatory HQ.  Nothing like a mysterious box, trailing wires out of the break-room refrigerator, connected to a little computer looking thingy to properly secure my status as an electronic hacker and geek.  No worries, that reputation is quite secure.<\/p>\n<p><figure id=\"attachment_21396\" aria-describedby=\"caption-attachment-21396\" style=\"width: 200px\" class=\"wp-caption alignright\"><a href=\"https:\/\/darkerview.com\/wordpress\/?attachment_id=21396\" rel=\"attachment wp-att-21396\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/darkerview.com\/wordpress\/wp-content\/uploads\/2017\/04\/BangBang-200x200.png\" alt=\"The performance of the bang-bang heater is a test run\" width=\"200\" height=\"200\" class=\"size-thumbnail wp-image-21396\" \/><\/a><figcaption id=\"caption-attachment-21396\" class=\"wp-caption-text\">The performance of the bang-bang heater is a test run<\/figcaption><\/figure>Looking closer at the chart will show the temperature falling to 10&deg;C where the heater is activated.  The temperature promptly rises past the turn off point at 15&deg;C where the heater turns off.  As you might note the temperature in the box keeps rising after the heater is off, no doubt due to the thermal energy stored in the mass of the heater plate and resistors radiating into the small insulated cardboard box.<\/p>\n<p>The chart also demonstrates the problems with a bang-bang controller.  There is a large swing in the controlled parameter, often an unacceptable swing.  Not a problem for this application, perhaps a problem for other uses.  Consider using this control swing to heat a room, many would find the result, alternating between too warm or too cold,  to be uncomfortable.<\/p>\n<p>Yes, you could move the control points closer, but there will be some swing simply due to the delays inherent in a large system where things take time to happen.  By the time the room heats up and the heater turns off it is already too late, the controlled parameter may overshoot the desired value by quite a bit.  Setting the control points closer also creates a system that turns on and off more rapidly.  Some equipment, such a gas-fired furnace, may not operate efficiently when cycled quickly.<\/p>\n<p>Heating and cooling are often controlled by bang-bang controllers, simple thermostats.  A furnace or air conditioner is an all-or-nothing device, you can turn it on or off, with nothing in between.  If you look closely at the programming of the thermostat you will find two settings&#8230; The desired temperature, and if you look closer the allowed temperature swing or hysteresis.<\/p>\n<p>If tighter control is required the usual answer is to move to some sort of <a href=\"https:\/\/en.wikipedia.org\/wiki\/PID_controller\" target=\"_blank\">proportional PID control<\/a> in place of the bang-bang.  Using a PID servo control scheme it is possible to tune the system to avoid large overshoots and achieve vastly better control of the system.  The price is a far more sophisticated design and the need to find the correct control parameters, often a challenging task.  There are entire textbooks on tuning PID servo loops!<\/p>\n<p>As you can see below, this circuit is extremely simple, the only real work is in the code.  Programming this little PIC micro is just fun.  There is not much you need to worry about.  Only a few control registers, only six I\/O pins of which I am using only two, the only peripherals I am using using are the A\/D converter and the timer.<\/p>\n<p>The PIC12C671 has been moved to the &#8220;not recommended for new designs&#8221; status by Microchip, superseded by the <a href=\"http:\/\/www.microchip.com\/wwwproducts\/en\/PIC12F675\" target=\"_blank\">PIC12C675<\/a>.  Why use it?  I still have a few sitting around in the parts pile, including a double handful of the UV-EPROM versions needed for development and testing. I did quite a few designs based on this little chip, mostly battery chargers, back during my employment for <a href=\"http:\/\/www.cdtechno.com\/\" target=\"_blank\">C&#038;D Technologies<\/a>.  I have some memories wrapped up in this little chip.<\/p>\n<p><!--more--><figure id=\"attachment_14035\" aria-describedby=\"caption-attachment-14035\" style=\"width: 150px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/darkerview.com\/wordpress\/?attachment_id=14035\" rel=\"attachment wp-att-14035\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/darkerview.com\/wordpress\/wp-content\/uploads\/2014\/08\/CG67-92-14213-DC-150x150.jpg\" alt=\"Keck CloudCam\" width=\"150\" height=\"150\" class=\"size-thumbnail wp-image-14035\" \/><\/a><figcaption id=\"caption-attachment-14035\" class=\"wp-caption-text\">The housing for the Keck CloudCam ready for the worst in Mauna Kea weather.<\/figcaption><\/figure>This heater is destined to be installed in <a href=\"https:\/\/darkerview.com\/wordpress\/?p=14032\" target=\"_blank\">CloudCam<\/a>.  We have found that if we lose the camera, usually due to a power outage, while the camera is cold, it will not reboot.  The camera will not respond until later in the day when the temperature warms up.  Power outages are often associated with the storms, just when we most want the cameras.  Answer?  Put a little heater in the case with the camera and keep it warm.<\/p>\n<p>The heating is minimal, about eight watts, but it should be enough to warm the small box containing the camera at least a few degrees.  This is about all I can draw from the power supply that also serves the camera and window heater.<\/p>\n<p>I have included the entire design here, both the schematic and the code.  Feel free to use any or all of it.  You will need MPLAB and a device programmer to program the microcontroller.  Otherwise the circuit is simple to build and should provide no difficulty.<\/p>\n<pre class=\"theme:obsidian tab-size:12 lang:asm decode:true\" title=\"BangBang.asm\" range=\"0-20\">;------------------------------------------------------------------------------\r\n;  BangBang.asm\r\n;  - simple bang-bang heater control based on a thermistor\r\n;\r\n;  Andrew Cooper\r\n;  http:\/\/www.darkerview.com\r\n;  CC BY-SA Creative Commons Share Alike\r\n;\r\n;  25Mar2017 A. Cooper\r\n;  - initial version\r\n;\r\n;------------------------------------------------------------------------------\r\n\tlist\tp=12c672\t;define processor\r\n\t#include\t<pic12c672.inc> ;processor specific stuff\r\n\terrorlevel\t-302\t;suppress message 302\r\n\t__CONFIG\t_CP_OFF&_WDT_OFF&_MCLRE_OFF&_PWRTE_ON&_INTRC_OSC\r\n\r\n\r\n;- RC Osc Calibration ---------------------------------------------------------\r\n\torg\t0x7FF\r\n\tretlw\t0x80\t;RC oscillator calibration constant\r\n\r\n\r\n;- Definitions ----------------------------------------------------------------\r\nhiThresh\tequ\t0x9A\t;high off threshold (15C)\r\nloThresh\tequ\t0xA6\t;lo on threshold (10C)\r\ntimeCal\tequ\t0x86\t;timer calibration for 1kHz\r\n\r\n;cross bank registers at 0x70\r\nmode\tequ\t0x70\t;mode control\r\ntemp\tequ\t0x71\t;current temperature\r\nadPtr\tequ\t0x72\t;pointer at AD averaging table\r\nfTime\tequ\t0x73\t;fast timer (1kHz)\r\nmTime\tequ\t0x74\t;medium timer (10Hz)\r\nsTime\tequ\t0x75\t;seconds\r\nwTemp\tequ\t0x78\t;interrupt context saving of W\r\nsTemp\tequ\t0x79\t;interrupt context saving of STATUS\r\ntemp1\tequ\t0x7A\t;scratch\r\ntemp2\tequ\t0x7B\r\ntemp3\tequ\t0x7C\r\ntemp4\tequ\t0x7D\r\n\r\n;aliases for scratch registers\r\nresHi\tequ\ttemp1\r\nresLo\tequ\ttemp2\r\ncount\tequ\ttemp4\r\n\r\n;analog results table\r\nadTbl\tequ\t0x20\t;AtoD averaging table\r\n\r\n;bits in mode\r\nheatOn\tequ\t0x0\t;heater on (high=true)\r\nadCk\tequ\t0x1\t;set to read AtoD (1Hz)\r\n\r\n;GPIO register\r\nheat\tequ\t0x4\t;heater output\r\n\r\n;- Reset ----------------------------------------------------------------------\r\nRst\torg\t0x000\t; processor reset vector\r\n\tgoto\tInit\t; go to beginning of program\r\n\r\n;- Interrupt Routine ----------------------------------------------------------\r\nInterrupt\torg\t0x004\r\n\tmovwf\twTemp\t;save context during interrupt\r\n\tmovf\tSTATUS,w\r\n\tmovwf\tsTemp\r\n\tincf\tfTime,f\t;increment fast 1kHz timer\r\n\tbanksel\tTMR0\r\n\tmovlw\ttimeCal\r\n\tmovwf\tTMR0\r\n\tbanksel\tINTCON\t;clear interrupt overflow bit\r\n\tbcf\tINTCON,T0IF\r\n\tmovf\tsTemp,w\t;restore context before return from int\r\n\tmovwf\tSTATUS\r\n\tswapf\twTemp,f\r\n\tswapf\twTemp,w\r\n\tretfie\t\t;return from interrupt\r\n\r\n;- Initialization -------------------------------------------------------------\r\nInit\tcall\t0x7FF\t;retrieve osc cal value\r\n\tbanksel\tOSCCAL\r\n\tmovwf\tOSCCAL\r\n\tbanksel\tTRISIO\t;set direction bits for outputs\r\n\tbcf\tTRISIO,heat\r\n\tcall\tTimeInit\t;set up timer0\r\n\tcall\tADInit\t;get AtoD going\r\n\tcall\tADFill\r\n\tclrf\tmode\t;clear control variables\r\n\r\n;- Main Code ------------------------------------------------------------------\r\nMain\tcall\tADRead\t;read temperature\r\n\tcall\tHeatCheck\t;check the heater status\r\n\tcall\tTimeKeep\t;update timers\r\n\tclrwdt\t\t;keep WDT cleared\r\n\tgoto\tMain\r\n\r\n;- Control --------------------------------------------------------------------\r\nHeatCheck\tbtfsc\tmode,heatOn\t;heater on?\r\n\t goto\tHeatCkOn\r\n\tbanksel\tGPIO\t;ensure heater is off\r\n\tbcf\tGPIO,heat\r\n\tmovf\ttemp,w\t;check temperature\r\n\tsublw\tloThresh\r\n\tbtfsc\tSTATUS,C\r\n\t return\r\n\tbsf\tmode,heatOn\r\n\treturn\r\nHeatCkOn\t\r\n\tbanksel\tGPIO\t;ensure heater is on\r\n\tbsf\tGPIO,heat\r\n\tmovf\ttemp,w\t;check temperature\r\n\tsublw\thiThresh\r\n\tbtfss\tSTATUS,C\r\n\t return\r\n\tbcf\tmode,heatOn\r\n\treturn\r\n\r\n;- AtoD Routines --------------------------------------------------------------\r\nADInit\tclrf\tadPtr\t;clear average table pointer\r\n\tbanksel\tADCON1\t;set for AN0 only\r\n\tmovlw\tb'11111110'\r\n\tmovwf\tADCON1\r\n\tbanksel\tADCON0\t;setup A\/D for channel 0\r\n\tmovlw\tb'10000001'\t;A\/D is on, Fosc\/32, chan 0\r\n\tmovwf\tADCON0\r\n\tbsf\tADCON0,GO\r\n\tbanksel\tPIE1\t;A\/D interrupt disabled\r\n\tbcf\tPIE1,ADIE\r\n\tbanksel\tPIR1\r\n\tbcf\tPIR1,ADIF\r\n\treturn\r\n\t\r\nADFill\tclrf\tadPtr\t;clear pointer, fresh table\r\n\tbanksel\tADCON0\t;start new conversion for next time\r\n\tbsf\tADCON0,GO\r\nADFillWait1\tbtfsc\tADCON0,GO\r\n\t goto\tADFillWait1\r\n\tbsf\tADCON0,GO\r\nADFillWait2\tbtfsc\tADCON0,GO\r\n\t goto\tADFillWait2\r\n\tmovlw\tadTbl\t;setup for table write\r\n\tmovwf\tFSR\r\n\tmovlw\t0x0F\r\n\tmovwf\tcount\r\n\tbanksel\tADRES\t;get current temp\r\n\tmovf\tADRES,w\r\nADFillWrite\tmovwf\tINDF\t;write table\r\n\tdecfsz\tcount,f\r\n\t goto\tADFillWrite\r\n\treturn\r\n\r\nADRead\tbtfss\tmode,adCk\t;time for sample?\r\n\t return\r\n\tbcf\tmode,adCk\r\n\tincf\tadPtr,w\t;setup table pointer\r\n\tandlw\t0x0F\r\n\tmovwf\tadPtr\r\n\taddlw\tadTbl\r\n\tmovwf\tFSR\r\n\tbanksel\tADRES\t;get result\r\n\tmovf\tADRES,w\r\n\tmovwf\tINDF\t;store result\r\n\tbanksel\tADCON0\t;start new conversion for next time\r\n\tbsf\tADCON0,GO\r\n\tclrf\tresLo\t;average table\r\n\tclrf\tresHi\r\n\tmovlw\tadTbl\t;set pointer\r\n\tmovwf\tFSR\r\n\tmovlw\t0x10\t;set counter\r\n\tmovwf\tcount\r\nADAvg\tmovf\tINDF,w\t;add data\r\n\taddwf\tresLo,f\r\n\tbtfsc\tSTATUS,C\r\n\t incf\tresHi,f\r\n\tincf\tFSR,f\t;repeat\r\n\tdecfsz\tcount,f\r\n\t goto\tADAvg\r\n\trrf\tresHi,f\t;divide for average\r\n\trrf\tresLo,f\r\n\trrf\tresHi,f\r\n\trrf\tresLo,f\r\n\trrf\tresHi,f\r\n\trrf\tresLo,f\r\n\trrf\tresHi,f\r\n\trrf\tresLo,w\r\n\tmovwf\ttemp\r\n\treturn\r\n\r\n;- Time -----------------------------------------------------------------------\r\nTimeInit\tclrwdt\t\t;clear WDT before prescaler assignment\r\n\tbanksel\tOPTION_REG\t;setup TMR0\r\n\tmovlw\tb'11000010'\t;prescaler to TMR0\r\n\t\t\t;prescaler set to 1:8\r\n\t\t\t;pullups disabled\r\n\t\t\t;TMR0 source internal\r\n\tmovwf\tOPTION_REG\r\n\tbanksel\tINTCON\t;set interrupts\r\n\tmovlw\tb'11100000'\t;TMR0 int enabled, all others disabled\r\n\tmovwf\tINTCON\r\n\treturn\r\n\t\r\nTimeKeep\tmovf\tfTime,w\t;check for 0.1 second interval\r\n\tsublw\t0x64\r\n\tbtfsc\tSTATUS,C\r\n\t return\r\n\tclrf\tfTime\r\n\tincf\tmTime,f\r\n\tmovf\tmTime,w\t;check for 1 second interval\r\n\tsublw\t0x09\r\n\tbtfsc\tSTATUS,C\r\n\t return\r\n\tclrf\tmTime\r\n\tincf\tsTime\t;count seconds\r\n\tbsf\tmode,adCk\t;check AtoD at 1Hz\r\n\treturn\r\n\r\n\tend\r\n;- End of BangBang ------------------------------------------------------------<\/pre>\n<p>The code is simple non-relocatable assembler, not much need for dynamic code arrangement in such a small project.  The resulting code consumes a whopping 138 bytes out of the two kilobytes available.  Only 28 bytes of RAM are needed, half of that is the averaging table for the analog data. Pretty simple!<\/p>\n<p>To further ensure stability of this controller the temperature is measured every second and averaged over the last 16 seconds as a boxcar average.  Thus the temperature value used for control only changes once each second and should change slowly.  Even if a wildly spurious value appears the boxcar average should devalue any stray readings.<\/p>\n<p><figure id=\"attachment_21392\" aria-describedby=\"caption-attachment-21392\" style=\"width: 200px\" class=\"wp-caption alignright\"><a href=\"https:\/\/darkerview.com\/wordpress\/?attachment_id=21392\" rel=\"attachment wp-att-21392\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/darkerview.com\/wordpress\/wp-content\/uploads\/2017\/03\/BangBangHeater-200x200.png\" alt=\"Bang Bang Heater Schematic\" width=\"200\" height=\"200\" class=\"size-thumbnail wp-image-21392\" \/><\/a><figcaption id=\"caption-attachment-21392\" class=\"wp-caption-text\">Bang Bang Heater Schematic<\/figcaption><\/figure>The circuit is likewise very, very simple.  A 10k thermistor provides the temperature reading, while a power darlington transistor switches a set of 5W power resistors.  The circuit is built on a small bit of perfboard while the transistor and resistors are secured to an aluminum plate with a heatsink to allow the heat to radiate into the enclosure.<\/p>\n<p>This sort of simple circuit may not present any huge engineering challenge, rather the fun lies in making the circuit elegant and robust, an expression of skill.  Everything needed came from the parts pile, nothing needed to be ordered.<\/p>\n<p>The hardware took a single evening to assemble, the aluminum bits manufactured in the observatory machine shop that afternoon.  The software likewise was done in a single day, something to do while taking breaks from cleaning the carpets and laundry on a busy Sunday.  Testing took a bit longer, but that was mostly just letting it run while a data logger kept watch.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I took a break from working with a &#8220;big&#8221; microcontroller to work with a little one. The PIC12C671 is definitely little when compared with the PIC18F66K80 I am using in the GenPIC utility PCB. With less than 2k of program space and a mere 128 bytes of RAM it is definitely limited. Consider that the &hellip; <a href=\"https:\/\/darkerview.com\/wordpress\/?p=21373\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Bang-Bang&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[253],"tags":[2399,414,1994,2376,2400],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/21373"}],"collection":[{"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=21373"}],"version-history":[{"count":5,"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/21373\/revisions"}],"predecessor-version":[{"id":21424,"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/21373\/revisions\/21424"}],"wp:attachment":[{"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/darkerview.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}