{"id":243,"date":"2013-06-19T10:28:19","date_gmt":"2013-06-19T10:28:19","guid":{"rendered":"http:\/\/ermine-electronics.co.uk\/?p=243"},"modified":"2018-02-24T21:13:15","modified_gmt":"2018-02-24T21:13:15","slug":"16f628-pic-ad-using-jal","status":"publish","type":"post","link":"https:\/\/www.richardmudhar.com\/blog\/2013\/06\/16f628-pic-ad-using-jal\/","title":{"rendered":"16F628 PIC A\/D using JAL"},"content":{"rendered":"<p>The 16F628 pic doesn&#8217;t actually have a A\/D converter. It has a couple of comparators and a software controllable voltage reference which does pretty well for most applications. I&#8217;m looking at using it for a low-battery cutoff device to protect 12V lead-acid batteries.The two comparators would work for that &#8211; one for the low-water mark, and one set a little bit above for a level the charge needs to reach before the load is reapplied, with some time delay probably too.<\/p>\n<p>However, I came across Microchip&#8217;s Application note <a href=\"http:\/\/www.microchip.com\/stellent\/idcplg?IdcService=SS_GET_PAGE&amp;nodeId=1824&amp;appnote=en011642\" target=\"_blank\" rel=\"noopener\">AN700 Make a Delta-Sigma Converter Using a Microcontroller&#8217;s Analog Comparator Module <\/a>which shows how to use the comparator as an A\/D\u00a0 converter. There are plenty of PICs that already have an A\/D converter &#8211; the 16F88 has several analogue channels, but the 16F628 is cheaper. A lot of applications need just one analogue value sampled, and my application also wants an A\/D that includes 12V. If I used a chip with an onboard A\/D I&#8217;m going to need two resistors anyway to pad 12V down to the 5V range, and AN700 fig 7 shows how to take advantage of the external parts to shift the A\/D range up to about 12V.<\/p>\n<p>Trouble is, I want to use JAL, to make life easier when I write the rest of the code, and the assembler mode of JAL didn&#8217;t work. I swiped this<a href=\"http:\/\/tech.groups.yahoo.com\/group\/jallist\/message\/29669\" target=\"_blank\" rel=\"noopener\"> from here<\/a> probably derived<a href=\"http:\/\/den-nekonoko.blog.so-net.ne.jp\/2010-11-25\" target=\"_blank\" rel=\"noopener\"> from here<\/a> but it didn&#8217;t work for me. I took a look at the code and suspected the assembler part, because what was happening was as soon as I called the DeltaSigA2D() the whole program seemed to sit down and start again from the top, resulting in endless printing of &#8220;STARTED&#8221; and little else.<\/p>\n<p>Thinking about what JAL is probably doing with assembler, I suspected some of the clever space-saving constructs like the bit in eat5cycles that goes<\/p>\n<p>goto +1<\/p>\n<p>which was supposed to be<\/p>\n<p>goto $+1<\/p>\n<p>could be asking for trouble unless I could really assume that next instruction is the next one in the program space. In the end if you&#8217;re going to use something like JAL you aren&#8217;t trying to eke out every last drop of code space, so I figured I would nut the cleverness and use stacked nops. And it worked.<\/p>\n<p>&nbsp;<\/p>\n<pre>-- JAL 2.4i\n-- Just the A\/D 15 June 2013\n-- modded by Richard\n--\n-- adc_test_16f628_v03\n-- after DeltaSig.asm v1.00 from Dan Butler, Microchip Technology Inc. 02 December 1998\n-- after http:\/\/den-nekonoko.blog.so-net.ne.jp\/2010-11-25 and AN700\n-- continually spews 10-bit value on TXD at 9600 baud, 5V=1024 0V=0\n-- AN700 Fig 2\ninclude 16f628_inc_all\n-- We'll use internal oscillator. It work @ 4MHz\npragma target clock\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4_000_000\nconst word _fuses\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = 0x3fff ; default value\npragma target osc\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 INTRC_NOCLKOUT\npragma target WDT\u00a0\u00a0\u00a0 off\npragma target MCLRE\u00a0 off\npragma target PWRTE\u00a0 on\npragma target BODEN\u00a0\u00a0\u00a0 on\npragma target LVP\u00a0\u00a0\u00a0 off\n-- HS, -BOD, ,-LVP, -WDT, -CP\u00a0 = 0x3F22\n; pragma target fuses\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0x3D02\n--enable_digital_io()\n\n; const bit enhanced_flash_eeprom = false\ninclude pic_general\ninclude delay\n\nvar word result\nvar byte result_l\nvar byte result_h\nvar byte counter1\nvar byte counter2\n\nconst byte booted[] = \"STARTED\"\n\npin_a0_direction = input\npin_a1_direction = input\npin_a2_direction = input ; comparator in \/ vref out\npin_a3_direction = output ; comp1 out\npin_a4_direction = output ; comp2 out (OD)\npin_b2_direction=output ; RS232 TX\n\nconst bit usart_hw_serial = TRUE\nconst serial_hw_baudrate = 9600\ninclude serial_hardware\nserial_hw_init()\n\ninclude print\ninclude format\n\nProcedure InitDeltaSigA2D() is\nVRCON=0b11101100 --\u00a0\u00a0\u00a0 0xEC\nCMCON=0b00000110\u00a0\u00a0 -- 0x06 two common ref comps with outputs\nend procedure\n\n;\n; Delta Sigma A2D\n; The below contains a lot of nops and goto next instruction. These\n; are necessary to ensure each pass through the Elop1 takes the same\n; amount of , no the path through the code.\n;\nProcedure DeltaSigA2D() is\nassembler\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 LOCAL\u00a0\u00a0\u00a0 elop1,comphigh,complow,eat2cycles,endelop1,eat5cycles,exit1\n--DeltaSigA2D\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 clrf counter1\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 clrf counter2\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 clrf result_l\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 clrf result_h\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 movlw 0x03 ; set up for 2 analog comparators with common reference\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 movwf cmcon\nelop1:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 btfsc c1out ; is comparator high or low?\n--\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 btfsc cmcon,c1out ; is comparator high or low?\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto complow ; go the low route\ncomphigh:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 nop ; necessary to timing even\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bcf porta,3 ; porta.3 = 0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 incfsz result_l,f ; bump counter\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto eat2cycles ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 incf result_h,f ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto endelop1 ;\ncomplow:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bsf porta,3 ; comparator is low\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 nop ; necessary to keep timing even\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto eat2cycles ; same here\neat2cycles:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto endelop1 ; eat 2 more cycles\nendelop1:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 incfsz counter1,f ; count this lap through the elop1.\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto eat5cycles ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 incf counter2,f ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 movf counter2,w ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 andlw 0x04 ; are we done? (we're done when bit2 of\n--\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 btfsc status,_z ; the high order byte overflows to 1).\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 btfsc Z --status,z ; the high order byte overflows to 1).\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto elop1 ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto exit1\neat5cycles:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 nop\u00a0 -- this really seems to hate the goto $+1, keeps resetting. I am not so short of code space, case to be made to turn everything into nops\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 nop\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 --goto +1 ; more wasted time to keep the elop1s even\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 nop ;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 goto elop1 ;\nexit1:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 movlw 0x06 ; set up for 2 analog comparators with common reference\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 movwf cmcon\nend assembler\nend procedure\n\nfunction rescale(WORD IN value) RETURN WORD is\n-- 1024 corresponds to 5V\n-- multiply by 50000\/1024 (~49)\nvar word temp =value*49\ntemp=temp\/100 -- now lose excess precision\nreturn temp\n\nend function\n\nInitDeltaSigA2D()\n\nprint_string(serial_hw_data,booted)\n\nforever loop\nDeltaSigA2D()\nresult=word(result_h)*256 + word(result_l) -- you must explicity make result_h a word as described on p11 of JAL manual\nresult=rescale(result)\nformat_word_dec(serial_hw_data, result, 3, 2)\nserial_hw_data = \" \"\nserial_hw_data = 13 -- CR\nserial_hw_data = 10 -- LF\ndelay_1ms(500)\u00a0\u00a0 -- this is purely to allow the terminal display to catch up and not overload buffer of the slow device\nend loop<\/pre>\n<p>Files<\/p>\n<p><a title=\"The JAL source for the ADC on a 16F628 PIC\" href=\"http:\/\/www.megalithia.com\/wp-content\/uploads\/files\/adc_test_16f628_v03.jal\" target=\"_blank\" rel=\"noopener\">adc_test_16f628_v03.jal<\/a><\/p>\n<p>and the hex file<\/p>\n<p><a title=\"hex file for the ADC on a 16F628 using JAL\" href=\"http:\/\/www.megalithia.com\/wp-content\/uploads\/files\/adc_test_16f628_v03.hex\" target=\"_blank\" rel=\"noopener\">adc_test_16f628_v03.hex <\/a><\/p>\n<p>There&#8217;s a case to be made for using a voltage reference and setting it to be some convenient power of 2 like 2.05 V to save all the messy integer calculation in rescale<\/p>\n<p>This is a video of the display on the serial port compared with a multimeter on the input, connected to a 5k pot between 0V and +5V. I should have moved the control a bit slower to allow the 0.5s sampling to catch up at times, but it shows it is reasonably accurate.<\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/AM0G0nrGX1o?feature=player_detailpage\" width=\"496\" height=\"360\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The 16F628 pic doesn&#8217;t actually have a A\/D converter. It has a couple of comparators and a software controllable voltage reference which does pretty well for most applications. I&#8217;m looking at using it for a low-battery cutoff device to protect 12V lead-acid batteries.The two comparators would work for that &#8211; one for the low-water mark, &hellip; <a href=\"https:\/\/www.richardmudhar.com\/blog\/2013\/06\/16f628-pic-ad-using-jal\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;16F628 PIC A\/D using JAL&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[57],"tags":[265,7],"class_list":["post-243","post","type-post","status-publish","format-standard","hentry","category-electronics","tag-microcontroller","tag-pic-micro"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5aOO7-3V","jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts\/243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/comments?post=243"}],"version-history":[{"count":2,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts\/243\/revisions"}],"predecessor-version":[{"id":3468,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/posts\/243\/revisions\/3468"}],"wp:attachment":[{"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/media?parent=243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/categories?post=243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.richardmudhar.com\/blog\/wp-json\/wp\/v2\/tags?post=243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}