{"id":15170,"date":"2023-05-24T06:02:34","date_gmt":"2023-05-24T10:02:34","guid":{"rendered":"https:\/\/embedded-lab.com\/blog\/?p=15170"},"modified":"2023-09-06T01:30:19","modified_gmt":"2023-09-06T05:30:19","slug":"mastering-the-silabs-c8051-microcontroller","status":"publish","type":"post","link":"https:\/\/embedded-lab.com\/blog\/mastering-the-silabs-c8051-microcontroller\/","title":{"rendered":"Mastering the SiLabs C8051 Microcontroller"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In a world where upgrades and advancements are constant, it is easy to overlook older technology in favour of newer, more advanced options. However, the case of 8051 microcontrollers defies this trend. Despite being considered relics of the past, there is still a significant demand for these microcontrollers. Manufacturers have revitalized the proven 8051 architecture by incorporating modern features such as ADCs and communication modules, transforming them into powerful, reliable and versatile devices.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image.png\" alt=\"\" class=\"wp-image-15171\" width=\"342\" height=\"320\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.silabs.com\/\">Silicon\nLaboratories (SiLabs)<\/a> is an American semiconductor-manufacturing company,\nsimilar to Microchip and STMicroelectronics. They are renowned for producing a\nwide range of semiconductor components, including both 8 and 32-bit\nmicrocontrollers. Notably, SiLabs is highly regarded for its RF chips and\nUSB-Serial converters such as CP2102.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In terms of their 8-bit MCU product line-up, SiLabs\noffers microcontrollers based on the well-established 8051 architecture.\nHowever, their MCUs go beyond being simple, traditional 8051 devices. Like\nother manufacturers like Nuvoton and STC, SiLabs enhances their MCUs with\nadditional modern hardware components such as DACs and communication\nperipherals. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SiLabs C8051 microcontrollers are recognized for their good performance, reliability, and scalability. They cater to the evolving needs of the embedded systems industry, whether it&#8217;s in the realm of consumer electronics, industrial automation, or smart home applications. These microcontrollers serve as a solid foundation for various projects, providing developers with a dependable and flexible platform.<\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Hardware<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The\nmajor hardware items I used for this work are as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>SiLabs C8051F330D\nMicrocontroller Development Board. This board features a 74HC595 seven-segment\ndisplay, four input buttons, a programmer-debugger interface, GPIO pin headers,\na buzzer, UART to RS232 converter and power pins. <\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-1.png\" alt=\"\" class=\"wp-image-15172\" width=\"433\" height=\"317\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-1.png 865w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-1-580x425.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-1-768x563.png 768w\" sizes=\"auto, (max-width: 433px) 100vw, 433px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The table below summarizes the feature of C8051F33x\nmicrocontrollers. Note only C8051F330 comes in PDIP package and this makes it\nbreadboard-friendly. &nbsp;&nbsp;<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-155.png\" alt=\"\" class=\"wp-image-15371\" width=\"440\" height=\"361\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-155.png 586w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-155-580x476.png 580w\" sizes=\"auto, (max-width: 440px) 100vw, 440px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The board has the schematic as shown below.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-3.png\" alt=\"\" class=\"wp-image-15174\" width=\"940\" height=\"623\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-3.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-3-580x384.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-3-768x509.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<ul class=\"wp-block-list\"><li>Silicon Labs USB-programmer-debugger. This will be needed to download codes into C8051 microcontrollers. <\/li><li><\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-4.png\" alt=\"\" class=\"wp-image-15175\" width=\"425\" height=\"218\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-4.png 849w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-4-580x297.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-4-768x393.png 768w\" sizes=\"auto, (max-width: 425px) 100vw, 425px\" \/><\/figure><\/div>\n\n\n\n<ul class=\"wp-block-list\"><li>Apart from these I have used\nvarious breakout boards and sensors. All of the items I used are common and inexpensive.&nbsp; <\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-5.png\" alt=\"\" class=\"wp-image-15176\" width=\"429\" height=\"110\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-5.png 858w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-5-580x148.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-5-768x196.png 768w\" sizes=\"auto, (max-width: 429px) 100vw, 429px\" \/><\/figure><\/div>\n\n\n\n<ul class=\"wp-block-list\"><li>I also recommend downloading\nthe latest datasheet, app notes and other tools of the C8051F330D\nmicrocontroller from the SiLabs\u2019 <a href=\"https:\/\/www.silabs.com\/documents\/public\/data-sheets\/C8051F33x.pdf\">official\nwebsite<\/a>.<\/li><\/ul>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Software Suite<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For coding, I\nused the following software:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>MikroC Pro for 8051 Compiler<\/strong><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This is a C compiler and IDE from <a href=\"https:\/\/www.mikroe.com\/\">MikroElektronika<\/a>. I chose MikroC Pro for 8051 for quick development and other facilities like their rich collection of libraries and utilities. MikroElektronika also has several hardware and software solutions for rapid prototyping and DIY. I have been using MikroC compilers for 8051, AVR and ARM microcontrollers for quite a long time and so far, personally I am satisfied with their products and services.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-6.png\" alt=\"\" class=\"wp-image-15177\" width=\"380\" height=\"380\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-6.png 507w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-6-150x150.png 150w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-6-90x90.png 90w\" sizes=\"auto, (max-width: 380px) 100vw, 380px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"> <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Si Labs Code Configuration\nWizard 2<\/strong><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">When it comes to working with a new microcontroller, the most tedious job is going through the functionalities of its internal registers, and without setting them up, we would never get the desired outcome. Any coder would need a good understanding of internal peripherals and something to speed up code development. Surely, no coder would like to waste time setting internal registers manually. To address this issue, most present-day embedded-hardware manufacturers have opted for software solutions like code generators, software libraries and board support packages. In the case of SiLabs\u2019 microcontrollers, we have the luck of using their free code generator software called <strong><em>Si Lab Code Configuration Wizard 2<\/em><\/strong>. This simple-to-use software can generate register initialization codes for all hardware peripherals in either C or ASM (assembly). Thus, a lot of coding effort is reduced significantly.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"792\" height=\"551\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-7.png\" alt=\"\" class=\"wp-image-15178\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-7.png 792w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-7-580x404.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-7-768x534.png 768w\" sizes=\"auto, (max-width: 792px) 100vw, 792px\" \/><\/figure><\/div>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Si Labs Flash Program Utility<\/strong><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Lastly, we would need software and hardware to flash code into our target microcontroller, and <strong><em>SiLabs Flash Program Utility<\/em><\/strong> is just that tool.&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-8.png\" alt=\"\" class=\"wp-image-15179\" width=\"329\" height=\"438\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Both Si Labs\u2019\nsoftware can be downloaded from <a href=\"https:\/\/www.silabs.com\/developers\/8-bit-8051-microcontroller-software-studio?tab=downloads\">here<\/a>.\n<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MikroC for 8051 can be downloaded from <a href=\"https:\/\/www.mikroe.com\/mikroc-8051\">here<\/a>.<\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">How to use Configuration Wizard 2\nCode Generator?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After running the software, the following screen would show up first. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-9.png\" alt=\"\" class=\"wp-image-15180\" width=\"940\" height=\"496\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-9.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-9-580x306.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-9-768x405.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">From here we have to choose the target microcontroller from family and part number.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-10.png\" alt=\"\" class=\"wp-image-15181\" width=\"940\" height=\"496\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-10.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-10-580x306.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-10-768x405.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The following screen pops up after chip selection. Note that it is empty as no peripheral has been initialized.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-11.png\" alt=\"\" class=\"wp-image-15182\" width=\"940\" height=\"496\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-11.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-11-580x306.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-11-768x405.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now we have to click the <em>\u201cPeripherals\u201d<\/em> tab and explore what peripherals the selected chip offers. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-12.png\" alt=\"\" class=\"wp-image-15183\" width=\"940\" height=\"497\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-12.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-12-580x307.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-12-768x406.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As an example, let\u2019s see the Port I\/O peripheral. On selecting it, the following window pops up and it shows all the GPIOs and the options we have for them.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-13.png\" alt=\"\" class=\"wp-image-15184\" width=\"940\" height=\"497\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-13.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-13-580x307.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-13-768x406.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The same applies to other peripherals such as the internal DAC.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-14.png\" alt=\"\" class=\"wp-image-15185\" width=\"940\" height=\"497\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-14.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-14-580x307.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-14-768x406.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">After setting up the hardware peripherals as per need, the software automatically generates a temporary initialization code with comments. The comments give some overview of our initialization. We can save it for future reference or just copy it to the MikroC compiler. In case of copying, we do not need to copy the <em>#include<\/em> directives. All we need are the register values. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-15.png\" alt=\"\" class=\"wp-image-15186\" width=\"940\" height=\"493\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-15.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-15-580x304.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-15-768x403.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">When changes are made in hardware peripheral settings, the generated code is automatically regenerated. <\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">How to use MikroC Pro for 8051?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MikroC Pro for 8051 is very simple to use. Like many C compilers, it uses a projected-based file-folder structural approach.&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"503\" height=\"232\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-16.png\" alt=\"\" class=\"wp-image-15188\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Thus, after running it, we should start by opening a new project unless we already have created one before.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-17.png\" alt=\"\" class=\"wp-image-15189\" width=\"940\" height=\"509\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-17.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-17-580x314.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-17-768x416.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Once we click \u201c<em>New Project<\/em>\u201d, a project wizard pops up and it guides us in creating a new project in a step-by-step approach.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-18.png\" alt=\"\" class=\"wp-image-15190\" width=\"940\" height=\"510\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-18.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-18-580x315.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-18-768x417.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The important\nthings that we need to define when creating a new project are:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Project Name<\/li><li>Project Location in our\ncomputer<\/li><li>Part Number or MCU<\/li><li>Clock Speed<\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-19.png\" alt=\"\" class=\"wp-image-15191\" width=\"940\" height=\"510\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-19.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-19-580x315.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-19-768x417.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we have to define the memory model. In most cases, the <em>\u201cSmall\u201d<\/em> memory model is chosen. Details about the memory model are discussed <a href=\"https:\/\/download.mikroe.com\/documents\/compilers\/mikroc\/8051\/help\/memory_models.htm\">here<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-20.png\" alt=\"\" class=\"wp-image-15192\" width=\"940\" height=\"509\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-20.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-20-580x314.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-20-768x416.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">There is an option to add additional user files such as custom libraries and files such as images, notes, etc. that are needed to be associated with the project under construction. Usually, I keep it empty and add my own fabricated libraries manually. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-21.png\" alt=\"\" class=\"wp-image-15193\" width=\"940\" height=\"509\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-21.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-21-580x314.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-21-768x416.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Lastly, the MikroC compiler comes with many prebuilt libraries. We should not include them at this stage as code conflicts are likely the other way. &nbsp;<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-22.png\" alt=\"\" class=\"wp-image-15194\" width=\"940\" height=\"510\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-22.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-22-580x315.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-22-768x417.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This completes a new project construction.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-23.png\" alt=\"\" class=\"wp-image-15195\" width=\"940\" height=\"510\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-23.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-23-580x315.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-23-768x417.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Once the wizard is completed and closed, we are good to go for coding.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-24.png\" alt=\"\" class=\"wp-image-15196\" width=\"940\" height=\"510\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-24.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-24-580x315.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-24-768x417.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We can begin coding by copying code generated by Configuration Wizard 2 and adding necessary built-in and personally-coded libraries. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-25.png\" alt=\"\" class=\"wp-image-15197\" width=\"940\" height=\"509\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-25.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-25-580x314.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-25-768x416.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">On successful code compilation, we get messages regarding memory usage (RAM and ROM) and generated files. Likewise, when there is an error, we get error messages, stating the source and cause of that error.<\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">How to use Silicon Laboratories\nFlash Utility?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The first screen that appears after running the software is shown below. Note at this stage no chip or programmer is connected. We would always be using C2 debug interface.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-26.png\" alt=\"\" class=\"wp-image-15198\" width=\"415\" height=\"559\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">After physically connecting a programmer and a chip, we have to click the connect button. Also note that after a successful connection, both the part number and programmer firmware version show up.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-27.png\" alt=\"\" class=\"wp-image-15199\" width=\"408\" height=\"549\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Once connected, we have to select the <em>\u201cDownload Hex File\/Go\/Stop\u201d<\/em> tab. Check the \u201c<em>Erase all Code Space before download\u201d<\/em> checkbox.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-28.png\" alt=\"\" class=\"wp-image-15200\" width=\"445\" height=\"601\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">We have to set the target hex file location by browsing its location in our computer. When the <em>\u201cDownload\u201d<\/em> button is clicked, the hex file is downloaded to the target chip.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-29.png\" alt=\"\" class=\"wp-image-15201\" width=\"459\" height=\"622\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">On successful download, a popup message box\nappears with checksum value. Now the downloaded code is ready to be run and so\nclicking the <em>\u201cGo\u201d<\/em> button, runs the downloaded code. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-30.png\" alt=\"\" class=\"wp-image-15202\" width=\"426\" height=\"577\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To stop the code from execution, we can click the <em>\u201cHalt\u201d<\/em> button and the code stops working. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-31.png\" alt=\"\" class=\"wp-image-15203\" width=\"504\" height=\"682\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-31.png 504w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-31-480x650.png 480w\" sizes=\"auto, (max-width: 504px) 100vw, 504px\" \/><\/figure><\/div>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">General Purpose Input-Output (GPIO) and Clock System<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Playing with the GPIOs of C8051 microcontrollers is very easy. GPIOs can be either open-drain inputs and push-pull type outputs. The arrangements are simply as shown below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-32.png\" alt=\"\" class=\"wp-image-15206\" width=\"457\" height=\"103\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-32.png 913w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-32-580x130.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-32-768x172.png 768w\" sizes=\"auto, (max-width: 457px) 100vw, 457px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The general block diagram for a C8051 GPIO pin is shown below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-33.png\" alt=\"\" class=\"wp-image-15207\" width=\"415\" height=\"183\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-33.png 830w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-33-580x256.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-33-768x339.png 768w\" sizes=\"auto, (max-width: 415px) 100vw, 415px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This arrangement is typical for all 8051-based microcontrollers. The subtle differences are the Schmitt-trigger and analogue input channels. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The clock system is also pretty straightforward. There is only one system clock and it can be fed with several clock sources. These include the internal low-frequency low accuracy oscillator, the programmable high-frequency internal clock generator or an external clock source which can be anything from a crystal oscillator to simple RC oscillators. Faster clocks are needed for fast data processing while slower clocks are intended for low power consumption. To vary clock speed, there are also clock dividers to scale clock sources according to requirement. All of these can be set in code. Refer to the block diagram below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-34.png\" alt=\"\" class=\"wp-image-15208\" width=\"470\" height=\"348\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-34.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-34-580x429.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-34-768x568.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA_Init(void);<br> void Port_IO_Init(void);<br> void Init_Device(void);<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char i = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; P1_0_bit = 1;<br> &nbsp; &nbsp; P1_1_bit = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;if(P1_4_bit == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i++;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp;switch(i)<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x83;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x82;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x81;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x80;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;default:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp;P1_0_bit ^= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp;P1_1_bit ^= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(100);<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0x03;<br> &nbsp; &nbsp; P1SKIP = 0x13;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-35.png\" alt=\"\" class=\"wp-image-15209\" width=\"705\" height=\"338\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-35.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-35-580x278.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-35-768x368.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To demonstrate both the clock system and the\nGPIOs, I used a simple LED blinking example. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two LEDs connected with P1.0 and P1.1 blink\nalternatively like a police light. These pins are set as push-pull outputs. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A push button connected with P1.4 is also set as an open-drain input. An open-drain input is not purely open from VDD as there is a weak internal pullup. The purpose of this button is to change the clock frequency by altering the clock divider. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0x03;<br> &nbsp; &nbsp; P1SKIP = 0x13;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">By default, the internal high-frequency oscillator is selected as the system clock source. This source is reasonably accurate for typical applications. Inside the code, the oscillator divider is altered to change the system clock frequency.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char i = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; P1_0_bit = 1;<br> &nbsp; &nbsp; P1_1_bit = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;if(P1_4_bit == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i++;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp;switch(i)<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x83;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x82;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x81;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;OSCICN = 0x80;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;default:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp;P1_0_bit ^= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp;P1_1_bit ^= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(100);<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since the software delay amount is fixed,\nchanging the system clock frequency alters the blink rate. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A word of caution that I would like to share at this point that is, the internal watchdog timer (WDT) is started but default and so we need to stop it before doing anything else. If this is not done then our code would seemingly not work at all as the WDT would repeatedly overflow and reset the microcontroller. In C8051s, the WDT is a part of the PCA module and so the PCA module needs to be configured as follows. &nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"534\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-36.png\" alt=\"\" class=\"wp-image-15210\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-36.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-36-580x330.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-36-768x437.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-37.png\" alt=\"\" class=\"wp-image-15211\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-37.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-37-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-37-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - GPIO &amp; Clock System\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/c6nSj4rbI-s?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Timer (TMR) \u2013 Countdown Timer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In digital electronics and embedded\nsystems, timing is literally everything and so this makes timers of any\nmicrocontroller very important. The C8051F330D microcontroller has 4 timers \u2013\nTimer 0 to Timer 3. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Timers 0 and 1 are similar\nto the ones we would expect with any standard 8051 microcontrollers. They can\nbe used as timers or counters. In counter mode, these timers can count external\npulses\/inputs. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Timers 2 and 3 are\nadditional timers and they have the same features and similar operating procedures.\nThese timers cannot be used as counters.&nbsp;\n<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Timers are the clock source for some internal hardware peripherals such as UARTs and SMBUS. All of these timers can be clocked with various clock sources. The table shown below summarizes the mode of operation of all of these timers. &nbsp;<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-38.png\" alt=\"\" class=\"wp-image-15213\" width=\"607\" height=\"274\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-38.png 607w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-38-580x262.png 580w\" sizes=\"auto, (max-width: 607px) 100vw, 607px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">All of these timers can be configured in various ways and at that moment things get complex. Fortunately for us, SiLabs\u2019 <em>Configuration Wizard 2<\/em> makes coding a lot easy as it takes care of setting these timers just like other hardware peripherals.&nbsp;&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code <\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_7_bit<br> &nbsp;<br> #define SET &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_4_bit<br> #define INC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_3_bit<br> #define DEC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_2_bit<br> #define ESC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_1_bit<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> signed int s = 0;<br> unsigned int ms = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void data_converter(unsigned int val);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_2_ISR(void) <br> iv IVT_ADDR_ET2 <br> ilevel 1<br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; ms++;<br> &nbsp; &nbsp; if(ms &gt; 999)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ms = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; s--;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(s &lt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TR2_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; TMR2CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void Timer_3_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (s \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((s % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((s % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (s % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; unsigned char set_time = 0;<br> &nbsp; Init_Device();<br> &nbsp;<br> &nbsp; while(1)<br> &nbsp; {<br> &nbsp; &nbsp; &nbsp; if(SET == 0)<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while(SET == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set_time = 1;<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; if(set_time == 1)<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(INC == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s++;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(s &gt;= 9999)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = 9999;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(DEC == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(s &lt;= 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(ESC == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TR2_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set_time = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR2RLL = 0x02;<br> &nbsp; &nbsp; TMR2RLH = 0xFC;<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xFE;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0xA0;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> &nbsp; &nbsp; LED_LATCH = 1;<br> &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; LED_DOUT = 0;<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-39.png\" alt=\"\" class=\"wp-image-15214\" width=\"705\" height=\"350\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-39.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-39-580x288.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-39-768x382.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this demo, two timers \u2013\nTimer 2 and 3 have been used to make a simple countdown timer. Timer 3 is used for\nmultiplexing the onboard seven-segment displays while Timer 2 is used as the\nactual countdown timer. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, let\u2019s see how the multiplexing is achieved. With reference to the schematic, the seven-segment displays are driven with a pair of 74HC595 serial-in-parallel-out (SIPO) shift registers. The shift registers are cascaded in series. This means that the final output of the first shift register is connected to the data input of the second shift register while clock and latch pins are shorted. With this configuration, we get a 16-bit wide shift register because the first shift register would shift out data to the second register. Using shift registers in this way allows us to expand three outputs from C8051F330D to literally unlimited number of outputs. Here we just need 16 outputs.&nbsp;&nbsp;  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">74HC595 SIPO registers take data serially in and the input data is shifted when there is a low to high clock transition. One shift register can hold up to 8 bits or one byte of data and so eight clock transitions are needed. The above function does this SIPO part.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now that we know how to transfer data through the shift registers, we can now focus on how the seven segments are lit. The first eight bits are used to select which seven-segment out of the four to be lit and the second eight bits following it write the code for the LEDs of the selected segment. After sending these two bytes, the shift registers are latched by raising their latch pins high from low, meaning that all outputs of the shift registers are updated. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_7_bit<br> &nbsp;<br> ....<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> ....<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The above code just writes one seven-segment display at a time but we have four seven-segment displays. All of them need to be updated in such a way that all of them appear to be displayed simultaneously at the same time. Therefore, they need to be updated at a fast refresh rate and in such a way that while updating them no other tasks are blocked. To achieve this, we need a timer with periodic interrupts. Here Timer 3 is used with about a 1ms periodic interrupt interval. The following math shows how to find the ideal timer auto-reload value to achieve the desired timer interrupt interval. Remember that Timer 3 has an auto-reload feature and so we just have to put the calculated value in our code once. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-40.png\" alt=\"\" class=\"wp-image-15215\" width=\"606\" height=\"253\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-40.png 606w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-40-580x242.png 580w\" sizes=\"auto, (max-width: 606px) 100vw, 606px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The code below shows the timer, system clock and interrupt settings generated by the <em>Configuration Wizard 2<\/em> code generator.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR2RLL = 0x02;<br> &nbsp; &nbsp; TMR2RLH = 0xFC;<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0xA0;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"> Inside Timer 3 interrupt, the value to be displayed by the seven segments are decoded bytewise and position-wise and the respective seven segment displays are updated. This process is repeated periodically every 1ms.  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_3_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (s \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((s % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((s % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (s % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timer 2 is set just like Timer 3 and for 1ms interrupt interval but unlike Timer 3, it is not left to run by default. This is so because we want the timer to run after we have set the countdown time in seconds. In the main loop, four onboard push buttons are used to set count down time and start the timer.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> while(1)<br> {<br> &nbsp; &nbsp; if(SET == 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp;while(SET == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp;set_time = 1;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; if(set_time == 1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s++;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(s &gt;= 9999)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = 9999;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(s &lt;= 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(ESC == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TR2_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;set_time = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> }; <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the interrupt subroutine of Timer 2, a pair of variables keep track of milliseconds and seconds. Upon every 1000ms (1s) count, the countdown second is decremented. The timer keeps running till the second count has reached zero. When the second count has reached zero the timer is stopped by clearing its timer run flag bit. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_2_ISR(void) <br> iv IVT_ADDR_ET2 <br> ilevel 1<br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; ms++;<br> &nbsp; &nbsp; if(ms &gt; 999)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ms = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; s--;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(s &lt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TR2_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; TMR2CN &amp;= 0x7F;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-41.png\" alt=\"\" class=\"wp-image-15216\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-41.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-41-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-41-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"527\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-42.png\" alt=\"\" class=\"wp-image-15217\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-42.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-42-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-42-768x431.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Timer\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/rU22K8fVgS0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Analogue Comparator (CP0) \u2013\nCapacitance Meter<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">C8051s come with analogue comparator hardware embedded with them. This comparator can be used to measure voltage levels and take decisions based on voltage levels. Analogue comparators can be used as low battery detectors, voltage threshold detectors, oscillators, etc. The block diagram of C8051F330D\u2019s comparator 0 (CP0) is shown below. From the block diagram above, we can see that several inputs can be used. Additionally, there are options for interrupt, hysteresis, synchronizer, output and others.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-43.png\" alt=\"\" class=\"wp-image-15219\" width=\"470\" height=\"442\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-43.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-43-580x545.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-43-768x721.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"LCD_2_Wire.c\"<br> #include \"lcd_print.c\"<br> &nbsp;<br> #define measure_button &nbsp; &nbsp; P1_4_bit<br> &nbsp;<br> #define sampling_R &nbsp; &nbsp; &nbsp; &nbsp; 10000.0<br> #define div_factor &nbsp; &nbsp; &nbsp; &nbsp; (sampling_R * 0.693147)<br> &nbsp;<br> #define us_per_tick &nbsp; &nbsp; &nbsp; &nbsp;0.9795918<br> #define scale_factor &nbsp; &nbsp; &nbsp; 50<br> &nbsp;<br> unsigned char ovf = 0;<br> unsigned char measurement_done = 0;<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Comparator_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void reset_timer_1(void);<br> unsigned int get_timer_1(void);<br> &nbsp;<br> void Timer_1_ISR(void)<br> iv IVT_ADDR_ET1 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; ovf++;<br> &nbsp; &nbsp; TF1_bit = 0;<br> }<br> &nbsp;<br> void Analog_Comparator_ISR(void) <br> iv IVT_ADDR_ECP0 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; if(CP0FIF_bit)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; measurement_done = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; TCON = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; P0_2_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; CP0FIF_bit = 0;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; float c = 0.0;<br> &nbsp; &nbsp; unsigned long cnt = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; LCD_init();<br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(0, 0);<br> &nbsp; &nbsp; LCD_putstr(\"Capacitance\/ F:\");<br> &nbsp;<br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((measure_button == 0) &amp;&amp; (measurement_done == 0))<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reset_timer_1();<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_putstr(\"Discharging! &nbsp;\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0MDIN = 0xFE;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0MDOUT = 0x06;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_2_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(4000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0MDIN = 0xFC;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0MDOUT = 0x04;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TCON = 0x40;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_2_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LCD_putstr(\"Measuring! &nbsp; &nbsp;\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(4000);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(measurement_done)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cnt = ovf;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cnt &lt;&lt;= 16;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cnt += get_timer_1();<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;c = ((cnt * us_per_tick) \/ div_factor);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;c *= scale_factor;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_goto(0, 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_putstr(\" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \");<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if((c &gt; 0.0) &amp;&amp; (c &lt; 10000000.0))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if((c &gt; 0) &amp;&amp; (c &lt; 1000))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_goto(12, 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_putstr(\"n\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else if((c &gt;= 1000.0) &amp;&amp; (c &lt; 10000000.0))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;c \/= 1000.0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_goto(12, 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_putstr(\"u\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;print_F(0, 1, c, 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_goto(0, 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_putstr(\"O.L\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;measurement_done = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMOD = 0x10;<br> }<br> &nbsp;<br> void Comparator_Init(void)<br> {<br> &nbsp; &nbsp; CPT0CN = 0x8A;<br> &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; CPT0CN &amp;= ~0x30;<br> &nbsp; &nbsp; CPT0MX = 0x00;<br> &nbsp; &nbsp; CPT0MD = 0x11;<br> }<br> &nbsp;<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDIN = 0xFC;<br> &nbsp; &nbsp; P0MDOUT = 0x04;<br> &nbsp; &nbsp; P1MDOUT = 0xC0;<br> &nbsp; &nbsp; P0SKIP = 0x07;<br> &nbsp; &nbsp; P1SKIP = 0xD0;<br> &nbsp; &nbsp; XBR1 = 0xC0;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x88;<br> &nbsp; &nbsp; EIE1 = 0x20;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Comparator_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void reset_timer_1(void)<br> {<br> &nbsp; &nbsp; ovf = 0;<br> &nbsp; &nbsp; TH1 = 0x00;<br> &nbsp; &nbsp; TL1 = 0x00;<br> }<br> &nbsp;<br> unsigned int get_timer_1(void)<br> {<br> &nbsp; &nbsp; unsigned int counts = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; counts = TH1;<br> &nbsp; &nbsp; counts &lt;&lt;= 8;<br> &nbsp; &nbsp; counts |= TL1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return counts;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-44.png\" alt=\"\" class=\"wp-image-15220\" width=\"705\" height=\"481\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-44.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-44-580x396.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-44-768x524.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this section, we will see how we can use the internal analogue comparator of a C8051 to measure unknown capacitance values of capacitors. The principle used is based on determining the time it takes to charge an unknown capacitor to a certain voltage level. Thus, two things are needed to be done in the program \u2013 firstly, comparing two voltage levels and secondly, timing the time taken for the comparator to change logic state.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The basic circuit looks like the one shown below: <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-45.png\" alt=\"\" class=\"wp-image-15221\" width=\"335\" height=\"320\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-45.png 670w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-45-580x553.png 580w\" sizes=\"auto, (max-width: 335px) 100vw, 335px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Before trying to measure the unknown\ncapacitor<strong><em> C?<\/em><\/strong>, it is discharged through the current-limiting\nresistor <strong><em>Rd<\/em><\/strong> by closing switch <strong><em>SW2<\/em><\/strong>. SW2 is not a\nphysical switch. The working of SW2 is done inside the microcontroller. The\ninverting input pin of the internal analogue comparator is temporarily set as\nan output and then it is set to logic zero for 4 seconds. The capacitor to be\nmeasured starts to discharge. Discharging the capacitor ensures that no\nresidual charge is present in it as such charge will definitely affect reading.\nAfter discharging SW2 is opened by declaring it as an input.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After discharging, switch <strong><em>SW1<\/em><\/strong> is closed and an internal timer is started. SW1 is just like SW2 and is not an external pin but rather an I\/O pin. The non-inverting pin of the comparator is set to half VDD by the voltage divider formed by resistors <strong><em>R1<\/em><\/strong> and <strong><em>R2<\/em><\/strong>. Thus, when SW1 is closed with the unknown capacitor fully discharged, logic high state is observed at the output side of the comparator. The unknown capacitor continues to charge via the sampling resistor <strong><em>Rs<\/em><\/strong>. When the voltage of the capacitor exceeds a value more than half VDD, the output state of the comparator is flipped low and SW1 is opened. Thus, a high-low transition is observed. When this transition occurs, the timer is stopped, a comparator interrupt is issued and some calculations are performed to back-calculate the capacitance of the unknown capacitor. &nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let us see the calculations.  <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-154.png\" alt=\"\" class=\"wp-image-15349\" width=\"608\" height=\"539\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-154.png 608w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-154-580x514.png 580w\" sizes=\"auto, (max-width: 608px) 100vw, 608px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">P0.0 and P0.1 are set as the open-drain analogue pins since these pins are comparator input pins. P0.2 is the capacitor charging pin or SW1. P1.4 is attached to an onboard push-button that will be used to trigger the measurement process when pressed.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDIN = 0xFC;<br> &nbsp; &nbsp; P0MDOUT = 0x04;<br> &nbsp; &nbsp; P1MDOUT = 0xC0;<br> &nbsp; &nbsp; P0SKIP = 0x07;<br> &nbsp; &nbsp; P1SKIP = 0xD0;<br> &nbsp; &nbsp; XBR1 = 0xC0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The comparator is set as follows. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Comparator_Init(void)<br> {<br> &nbsp; &nbsp; CPT0CN = 0x8A;<br> &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; CPT0CN &amp;= ~0x30;<br> &nbsp; &nbsp; CPT0MX = 0x00;<br> &nbsp; &nbsp; CPT0MD = 0x11;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With these\nsettings, the comparator is set with 10mV hysteresis on both inputs, fast\nresponse time and falling-edge comparator interrupt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The system clock is set to 12.25MHz using the internal RC oscillator.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The timer used for timing in this example is Timer 1. It is set as a Mode 1 timer with a prescalar of 12 and with overflow interrupt enabled. However, it is not started in the beginning. It will be started during measurement. In this way, one tick of the timer is about 979ns.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMOD = 0x10;<br> } <\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"610\" height=\"173\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-47.png\" alt=\"\" class=\"wp-image-15223\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-47.png 610w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-47-580x164.png 580w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The main loop has two parts. The first part is about discharging and charging the unknown capacitor. When the push-button is pressed, the timer is reset and the discharge procedure is started by setting the proper logic states of the pin as mentioned earlier. After completing the discharge procedure, the I\/O pins are reconfigured and the timer is started as soon as the charging process is initiated.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> if((measure_button == 0) &amp;&amp; (measurement_done == 0))<br> {<br> &nbsp;&nbsp;&nbsp; reset_timer_1();<br> &nbsp;&nbsp;&nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; LCD_putstr(\"Discharging! &nbsp;\");<br> &nbsp; &nbsp; P0MDIN = 0xFE;<br> &nbsp; &nbsp; P0MDOUT = 0x06;<br> &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; P0_2_bit = 0;<br> &nbsp; &nbsp; delay_ms(4000);<br> &nbsp; &nbsp; P0MDIN = 0xFC;<br> &nbsp; &nbsp; P0MDOUT = 0x04;<br> &nbsp; &nbsp; TCON = 0x40;<br> &nbsp; &nbsp; P0_2_bit = 1;<br> &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; LCD_putstr(\"Measuring! &nbsp; &nbsp;\");<br> &nbsp; &nbsp; delay_ms(4000);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After completing the aforementioned steps, the code waits for the comparator interrupt.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Analog_Comparator_ISR(void) <br> iv IVT_ADDR_ECP0 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; if(CP0FIF_bit)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; measurement_done = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; TCON = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; P0_2_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; CP0FIF_bit = 0;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the comparator interrupt is triggered,\nthe timer and the charging process are both stopped.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We have already seen what math is needed to convert timer count to capacitance value and this second part of the main code is all about so. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> if(measurement_done)<br> {<br> &nbsp;&nbsp;&nbsp; cnt = ovf;<br> &nbsp; &nbsp; cnt &lt;&lt;= 16;<br> &nbsp; &nbsp; cnt += get_timer_1();<br> &nbsp; &nbsp; c = ((cnt * us_per_tick) \/ div_factor);<br> &nbsp; &nbsp; c *= scale_factor;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; LCD_putstr(\" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \");<br> &nbsp;<br> &nbsp; &nbsp; if((c &gt; 0.0) &amp;&amp; (c &lt; 10000000.0))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if((c &gt; 0) &amp;&amp; (c &lt; 1000))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_goto(12, 0);<br> &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_putstr(\"n\");<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if((c &gt;= 1000.0) &amp;&amp; (c &lt; 10000000.0))<br> &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br> &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;c \/= 1000.0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD_goto(12, 0);<br> &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;LCD_putstr(\"u\");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print_F(0, 1, c, 1);<br> &nbsp;&nbsp;&nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_goto(0, 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_putstr(\"O.L\");<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; measurement_done = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timer 1 interrupt is used to check if the timer overflowed during measurement. This should only be taken into account when measuring large-value capacitors. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_1_ISR(void)<br> iv IVT_ADDR_ET1 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; ovf++;<br> &nbsp; &nbsp; TF1_bit = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike most other examples covered in this document, an I2C LCD is used to show data. The code for the I2C LCD has been shared and it is the same as the ones I used with my past documents on various platforms. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"> The overall performance of such a capacitance meter is satisfactory and the results are accurate enough for most cases. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"534\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-48.png\" alt=\"\" class=\"wp-image-15224\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-48.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-48-580x330.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-48-768x437.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"522\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-49.png\" alt=\"\" class=\"wp-image-15225\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-49.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-49-580x322.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-49-768x426.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Analogue Comparator - Capacitance Meter\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/C-Gg1HH_d3s?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Analogue-to-Digital Converter (ADC) &#8211; Analogue Thermometer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">An Analogue-to-Digital Converter (ADC) is a must in any modern-era microcontroller and fortunately, C8051s come with 10-bit 200kbps differential successive-approximation register (SAR) ADCs, unlike traditional ones which are fully digital devices. It is quite advanced in terms of features. In the case of C8051F330D, all pins can be used with it. Two internal analogue multiplexers take care of the pin selection task. Additionally, there is an internal temperature sensor, an internal reference source, an analogue window comparator and tons of other kinds of stuff. The ADC can be triggered by several sources and it also supports interrupts. However, the best features of this ADC are the support for differential inputs and its SAR-type build-up. SAR ADCs are fast compared to other ADC types. The block diagram of the internal ADC of C8051F330D is shown below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-50.png\" alt=\"\" class=\"wp-image-15227\" width=\"470\" height=\"272\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-50.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-50-580x335.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-50-768x444.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp;P1_6_bit<br> #define LED_CLK &nbsp; P1_5_bit<br> #define LED_LATCH P1_7_bit<br> &nbsp;<br> #define ADC_res &nbsp; &nbsp;1023.0<br> #define VDD_mv &nbsp; &nbsp; 3300.0<br> &nbsp;<br> unsigned char i = 0;<br> unsigned char pt = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init();<br> void Port_IO_Init();<br> void Oscillator_Init();<br> void Interrupts_Init();<br> void ADC_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos, unsigned char point);<br> unsigned int adc_read(void);<br> void Voltage_Reference_Init(void);<br> unsigned int adc_avg(unsigned char channel);<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pt = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pt = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pt = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pt = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i, pt);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; float t = 0;<br> &nbsp; <br> &nbsp; Init_Device();<br> &nbsp; <br> &nbsp; while(1)<br> &nbsp; {<br> &nbsp; &nbsp; &nbsp;t = (adc_avg(0) * VDD_mv);<br> &nbsp; &nbsp; &nbsp;t \/= ADC_res;<br> &nbsp; &nbsp; &nbsp;value = ((t * 10) \u2013 5000);<br> &nbsp; &nbsp; &nbsp;delay_ms(100);<br> &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init()<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init()<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDIN = 0xFE;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x01;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init()<br> {<br> &nbsp; &nbsp; OSCLCN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init()<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void ADC_Init(void)<br> {<br> &nbsp; &nbsp; AMX0P = 0x00;<br> &nbsp; &nbsp; AMX0N = 0x11;<br> &nbsp; &nbsp; ADC0CF = 0x58;<br> &nbsp; &nbsp; ADC0CN = 0x80;<br> }<br> &nbsp;<br> void Voltage_Reference_Init(void)<br> {<br> &nbsp; &nbsp; REF0CN = 0x0A;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> &nbsp; &nbsp; ADC_Init();<br> &nbsp; &nbsp; Voltage_Reference_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos, unsigned char point)<br> {<br> &nbsp; &nbsp; unsigned char write_value = segment_code[disp];<br> &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; if(point)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; write_value &amp;= segment_code[10];<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(write_value);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> }<br> &nbsp;<br> unsigned int adc_read(void)<br> {<br> &nbsp; &nbsp;unsigned int ad_value = 0;<br> &nbsp;<br> &nbsp; &nbsp;ad_value = ADC0H;<br> &nbsp; &nbsp;ad_value &lt;&lt;= 8;<br> &nbsp; &nbsp;ad_value |= ADC0L;<br> &nbsp; &nbsp;<br> &nbsp; &nbsp;return ad_value;<br> }<br> &nbsp;<br> unsigned int adc_avg(unsigned char channel)<br> {<br> &nbsp; &nbsp; unsigned int avg_value = 0;<br> &nbsp; &nbsp; signed char samples = 16;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; AMX0P = (channel &amp; 0x1F);<br> &nbsp; &nbsp; delay_ms(1);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(samples &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; AD0INT_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; AD0BUSY_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; while(AD0INT_bit == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; avg_value += adc_read();<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; samples--;<br> &nbsp; &nbsp; };<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; avg_value &gt;&gt;= 4;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return avg_value;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-51.png\" alt=\"\" class=\"wp-image-15228\" width=\"705\" height=\"359\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-51.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-51-580x295.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-51-768x391.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">TMP36 is a very popular analogue temperature\nsensor apart from LM35. It gives voltage output that is proportional to\ntemperature and has an accuracy of 10mV\/\u00b0C. With an ADC we can read this sensor and determine the temperature\nit is sensing. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, we have to declare the pin that we will be using with the ADC. In this example, P0.0 pin is used and so it is set as open-drain analogue input. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init()<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDIN = 0xFE;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x01;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Like most of the examples, the system clock is derived from the internal RC oscillator and is set to 12.25MHz.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init()<br> {<br> &nbsp; &nbsp; OSCLCN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that the ADC is differential in terms of input. Since we are using only one channel, i.e., the positive input of the ADC, the negative input has to be tied to the ground. The ADC clock is set to 1MHz which is good enough for most applications considering Nyquist theory. Software-based trigger-polling method is used. ADC readings are set to be right-justified. These all are set as per the ADC initialization code shown below:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void ADC_Init(void)<br> {<br> &nbsp; &nbsp; AMX0P = 0x00;<br> &nbsp; &nbsp; AMX0N = 0x11;<br> &nbsp; &nbsp; ADC0CF = 0x58;<br> &nbsp; &nbsp; ADC0CN = 0x80;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">All ADC measurements have to be done with respect to a reference voltage source and in this example, VDD is used as the reference source. Internal analogue peripherals need to be biased by the internal bias generator. All these are part of the internal reference source peripheral and so these settings are set by tweaking the internal reference source configuration register.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Voltage_Reference_Init(void)<br> {<br> &nbsp; &nbsp; REF0CN = 0x0A;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The ADC can be read using the following function. It lets the user select a single channel and take an average of 16 samples. The ADC is first triggered by a software trigger and then the ADC conversion completion flag is polled. After polling, the ADC is read. The ADC readings are summed and stored. After acquiring 16 samples, the summed reading is right-shifted by a factor of 4. This shifting is just like dividing by 16 because                                                  2^4 = 16.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned int adc_avg(unsigned char channel)<br> {<br> &nbsp; &nbsp; unsigned int avg_value = 0;<br> &nbsp; &nbsp; signed char samples = 16;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; AMX0P = (channel &amp; 0x1F);<br> &nbsp; &nbsp; delay_ms(1);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(samples &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; AD0INT_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; AD0BUSY_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; while(AD0INT_bit == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; avg_value += adc_read();<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; samples--;<br> &nbsp; &nbsp; };<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; avg_value &gt;&gt;= 4;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return avg_value;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since the ADC reading is right-justified, the 10-bit ADC reading is done as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned int adc_read(void)<br> {<br> &nbsp; &nbsp;unsigned int ad_value = 0;<br> &nbsp;<br> &nbsp; &nbsp;ad_value = ADC0H;<br> &nbsp; &nbsp;ad_value &lt;&lt;= 8;<br> &nbsp; &nbsp;ad_value |= ADC0L;<br> &nbsp; &nbsp;<br> &nbsp; &nbsp;return ad_value;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The high byte is\nread first and then the low byte is read. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the main loop, the average ADC reading is obtained and the ADC count is converted to millivolts. The millivolt value is then converted to temperature.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; float t = 0;<br> &nbsp; <br> &nbsp; Init_Device();<br> &nbsp; <br> &nbsp; while(1)<br> &nbsp; {<br> &nbsp; &nbsp; &nbsp;t = (adc_avg(0) * VDD_mv);<br> &nbsp; &nbsp; &nbsp;t \/= ADC_res;<br> &nbsp; &nbsp; &nbsp;value = ((t * 10) \u2013 5000);<br> &nbsp; &nbsp; &nbsp;delay_ms(100);<br> &nbsp; };<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The math behind these steps in as follows. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, we need to determine the voltage output from the sensor. This is done using the formula below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-52.png\" alt=\"\" class=\"wp-image-15229\" width=\"602\" height=\"77\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-52.png 602w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-52-580x74.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-52-600x77.png 600w\" sizes=\"auto, (max-width: 602px) 100vw, 602px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">If we check the datasheet of the TMP36 sensor, we can see the sensor output voltage vs temperature relation along with the output scaling voltage and offset voltage values. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-53.png\" alt=\"\" class=\"wp-image-15230\" width=\"375\" height=\"292\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-53.png 749w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-53-580x451.png 580w\" sizes=\"auto, (max-width: 375px) 100vw, 375px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-54.png\" alt=\"\" class=\"wp-image-15231\" width=\"436\" height=\"140\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-54.png 872w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-54-580x186.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-54-768x247.png 768w\" sizes=\"auto, (max-width: 436px) 100vw, 436px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Using the graph and the info above, we can determine the following temperature versus voltage relation:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-55.png\" alt=\"\" class=\"wp-image-15232\" width=\"606\" height=\"55\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-55.png 606w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-55-580x53.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-55-600x55.png 600w\" sizes=\"auto, (max-width: 606px) 100vw, 606px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To display the temperature on the onboard seven-segment display, the above equation is scaled by a factor of 100 and so it changes to the following:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-56.png\" alt=\"\" class=\"wp-image-15233\" width=\"606\" height=\"49\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-56.png 606w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-56-580x47.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-56-600x49.png 600w\" sizes=\"auto, (max-width: 606px) 100vw, 606px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"523\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-57.png\" alt=\"\" class=\"wp-image-15234\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-57.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-57-580x323.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-57-768x428.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"884\" height=\"497\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-58.png\" alt=\"\" class=\"wp-image-15235\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-58.png 884w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-58-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-58-768x432.png 768w\" sizes=\"auto, (max-width: 884px) 100vw, 884px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - ADC (TMP36) &amp; Timer (74HC595 Seven Segment Displays)\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/IIkpdQ5EISQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Digital-to-Analogue Converter (IDA0)\n\u2013 Digital Signal Synthesizer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Digital-to-Analogue Converter (DAC) is just the converse hardware with respect to the ADC. With the exception of ARM microcontrollers and some modern microcontrollers such as the ATXMega series, DAC is not present in common devices and we have to use external DAC chips like the MCP4921 if we need one in a project. Fortunately, C8051F330D has one 10-bit DAC which can be used for a number of applications including audio generation, waveform generation, etc. Unlike most DACs which provide voltage outputs, the DAC present in C8051F330D provides current output instead of voltage output. With a suitable load resistor, we can convert the output current from the DAC to voltage. The block diagram below shows the contents of the DAC. The DAC can be triggered by a number of sources including all timers. These trigger sources are used to update DAC output. Two registers hold the 10-bit digital count that would be converted to current. The digital count is latched upon trigger. Through register coding, it is also possible to set the maximum full-scale current which can be 0.5mA, 1.0mA or 2.0mA.&nbsp;&nbsp;  <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-59.png\" alt=\"\" class=\"wp-image-15237\" width=\"389\" height=\"222\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-59.png 778w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-59-580x331.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-59-768x438.png 768w\" sizes=\"auto, (max-width: 389px) 100vw, 389px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; P1_7_bit<br> &nbsp;<br> #define MODE_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_3_bit<br> #define INC_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_2_bit<br> #define DEC_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_1_bit<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> const unsigned int code LUT_sine[32] =<br> {<br> &nbsp; &nbsp; 512,<br> &nbsp; &nbsp; 615,<br> &nbsp; &nbsp; 714,<br> &nbsp; &nbsp; 804,<br> &nbsp; &nbsp; 882,<br> &nbsp; &nbsp; 946,<br> &nbsp; &nbsp; 991,<br> &nbsp; &nbsp; 1017,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1007,<br> &nbsp; &nbsp; 971,<br> &nbsp; &nbsp; 916,<br> &nbsp; &nbsp; 845,<br> &nbsp; &nbsp; 760,<br> &nbsp; &nbsp; 665,<br> &nbsp; &nbsp; 564,<br> &nbsp; &nbsp; 460,<br> &nbsp; &nbsp; 359,<br> &nbsp; &nbsp; 264,<br> &nbsp; &nbsp; 179,<br> &nbsp; &nbsp; 108,<br> &nbsp; &nbsp; 53,<br> &nbsp; &nbsp; 17,<br> &nbsp; &nbsp; 2,<br> &nbsp; &nbsp; 7,<br> &nbsp; &nbsp; 33,<br> &nbsp; &nbsp; 78,<br> &nbsp; &nbsp; 142,<br> &nbsp; &nbsp; 220,<br> &nbsp; &nbsp; 310,<br> &nbsp; &nbsp; 409,<br> &nbsp; &nbsp; 512<br> };<br> &nbsp;<br> const unsigned int code LUT_triangle[32] =<br> {<br> &nbsp; &nbsp; 512,<br> &nbsp; &nbsp; 576,<br> &nbsp; &nbsp; 640,<br> &nbsp; &nbsp; 704,<br> &nbsp; &nbsp; 768,<br> &nbsp; &nbsp; 832,<br> &nbsp; &nbsp; 896,<br> &nbsp; &nbsp; 960,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 960,<br> &nbsp; &nbsp; 896,<br> &nbsp; &nbsp; 832,<br> &nbsp; &nbsp; 768,<br> &nbsp; &nbsp; 704,<br> &nbsp; &nbsp; 640,<br> &nbsp; &nbsp; 576,<br> &nbsp; &nbsp; 512,<br> &nbsp; &nbsp; 448,<br> &nbsp; &nbsp; 384,<br> &nbsp; &nbsp; 320,<br> &nbsp; &nbsp; 256,<br> &nbsp; &nbsp; 192,<br> &nbsp; &nbsp; 128,<br> &nbsp; &nbsp; 64,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 64,<br> &nbsp; &nbsp; 128,<br> &nbsp; &nbsp; 192,<br> &nbsp; &nbsp; 256,<br> &nbsp; &nbsp; 320,<br> &nbsp; &nbsp; 384,<br> &nbsp; &nbsp; 448<br> };<br> &nbsp;<br> const unsigned int code LUT_square[32] =<br> {<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void DAC_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> void DAC_write(unsigned int dac_value);<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; signed char l = 0;<br> &nbsp; &nbsp; unsigned int j = 0;<br> &nbsp; &nbsp; signed int dly = 0;<br> &nbsp; &nbsp; unsigned int dac_data = 0;<br> &nbsp; &nbsp; unsigned char mode = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(MODE_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(mode &gt;= 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(dly &gt; 9999)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly--;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(dly &lt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly = 9999;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; value = dly;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = LUT_triangle[l];<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = LUT_square[l];<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = LUT_sine[l];<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; l++;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(l &gt;= 32)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;l = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; DAC_write(dac_data);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; dly; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_us(1);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void DAC_Init(void)<br> {<br> &nbsp; &nbsp; IDA0CN = 0xF2;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDIN = 0xFD;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x02;<br> &nbsp; &nbsp; P1SKIP = 0xEE;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; DAC_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> }<br> &nbsp;<br> void DAC_write(unsigned int dac_value)<br> {<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; dac_value &lt;&lt;= 0x06;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; lb = (dac_value &amp; 0xC0);<br> &nbsp; &nbsp; hb = ((dac_value &amp; 0xFF00) &gt;&gt; 0x08);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; IDA0L = lb;<br> &nbsp; &nbsp; IDA0H = hb;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-60.png\" alt=\"\" class=\"wp-image-15238\" width=\"705\" height=\"362\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-60.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-60-580x298.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-60-768x395.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, the internal DAC is used to\ngenerate waveforms digitally \u2013 sinusoidal, triangular and square waves. The\nresult is a Digital Signal Synthesizer (DSS). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, the system clock is set to 12.25MHz and is derived from internal oscillator.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">C8051\u2019s DAC is set up just by setting the&nbsp;<em>IDA0CN&nbsp;<\/em>register. We need to enable the DAC, define its full-scale current value, and the source that would issue a new write sequence and the output pin.&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void DAC_Init(void)<br> {<br> &nbsp; &nbsp; IDA0CN = 0xF2;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The DAC takes 10-bit integer inputs that are separated by two registers and so we need a function to load these registers. This is done by the following function. Notice how the two registers are arranged and loaded. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-61.png\" alt=\"\" class=\"wp-image-15239\" width=\"432\" height=\"38\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-61.png 864w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-61-580x50.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-61-768x67.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-61-860x75.png 860w\" sizes=\"auto, (max-width: 432px) 100vw, 432px\" \/><\/figure><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\"> void DAC_write(unsigned int dac_value)<br> {<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; dac_value &lt;&lt;= 0x06;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; lb = (dac_value &amp; 0xC0);<br> &nbsp; &nbsp; hb = ((dac_value &amp; 0xFF00) &gt;&gt; 0x08);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; IDA0L = lb;<br> &nbsp; &nbsp; IDA0H = hb;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Three lookup table arrays for three types of waveforms hold the 10-bit values that would be put into the DAC input register. Alternatively, equations could have been used but that would require mathematical computations and would slow down the wave-generation process. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> const unsigned int code LUT_sine[32] =<br> {<br> &nbsp; &nbsp; 512,<br> &nbsp; &nbsp; 615,<br> &nbsp; &nbsp; 714,<br> &nbsp; &nbsp; 804,<br> &nbsp; &nbsp; 882,<br> &nbsp; &nbsp; 946,<br> &nbsp; &nbsp; 991,<br> &nbsp; &nbsp; 1017,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1007,<br> &nbsp; &nbsp; 971,<br> &nbsp; &nbsp; 916,<br> &nbsp; &nbsp; 845,<br> &nbsp; &nbsp; 760,<br> &nbsp; &nbsp; 665,<br> &nbsp; &nbsp; 564,<br> &nbsp; &nbsp; 460,<br> &nbsp; &nbsp; 359,<br> &nbsp; &nbsp; 264,<br> &nbsp; &nbsp; 179,<br> &nbsp; &nbsp; 108,<br> &nbsp; &nbsp; 53,<br> &nbsp; &nbsp; 17,<br> &nbsp; &nbsp; 2,<br> &nbsp; &nbsp; 7,<br> &nbsp; &nbsp; 33,<br> &nbsp; &nbsp; 78,<br> &nbsp; &nbsp; 142,<br> &nbsp; &nbsp; 220,<br> &nbsp; &nbsp; 310,<br> &nbsp; &nbsp; 409,<br> &nbsp; &nbsp; 512<br> };<br> &nbsp;<br> const unsigned int code LUT_triangle[32] =<br> {<br> &nbsp; &nbsp; 512,<br> &nbsp; &nbsp; 576,<br> &nbsp; &nbsp; 640,<br> &nbsp; &nbsp; 704,<br> &nbsp; &nbsp; 768,<br> &nbsp; &nbsp; 832,<br> &nbsp; &nbsp; 896,<br> &nbsp; &nbsp; 960,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 960,<br> &nbsp; &nbsp; 896,<br> &nbsp; &nbsp; 832,<br> &nbsp; &nbsp; 768,<br> &nbsp; &nbsp; 704,<br> &nbsp; &nbsp; 640,<br> &nbsp; &nbsp; 576,<br> &nbsp; &nbsp; 512,<br> &nbsp; &nbsp; 448,<br> &nbsp; &nbsp; 384,<br> &nbsp; &nbsp; 320,<br> &nbsp; &nbsp; 256,<br> &nbsp; &nbsp; 192,<br> &nbsp; &nbsp; 128,<br> &nbsp; &nbsp; 64,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 64,<br> &nbsp; &nbsp; 128,<br> &nbsp; &nbsp; 192,<br> &nbsp; &nbsp; 256,<br> &nbsp; &nbsp; 320,<br> &nbsp; &nbsp; 384,<br> &nbsp; &nbsp; 448<br> };<br> &nbsp;<br> const unsigned int code LUT_square[32] =<br> {<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023,<br> &nbsp; &nbsp; 1023<br> }; <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Three buttons are used to control the DSS. Pressing the button attached to P1.3 switches waveform types while pressing the buttons connected to P1.1 and P1.2 changes the frequency of the output waveform. This is the task inside the main loop. The onboard display gives an indication of period.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; signed char l = 0;<br> &nbsp; &nbsp; unsigned int j = 0;<br> &nbsp; &nbsp; signed int dly = 0;<br> &nbsp; &nbsp; unsigned int dac_data = 0;<br> &nbsp; &nbsp; unsigned char mode = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(MODE_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(mode &gt;= 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(dly &gt; 9999)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly--;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(dly &lt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dly = 9999;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; value = dly;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = LUT_triangle[l];<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = LUT_square[l];<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dac_data = LUT_sine[l];<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; l++;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(l &gt;= 32)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;l = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; DAC_write(dac_data);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; dly; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_us(1);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-62.png\" alt=\"\" class=\"wp-image-15240\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-62.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-62-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-62-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Digital-to-Analogue Converter (DAC) - Digital Signal Synthesizer (DSS)\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/uiA3NKKdNno?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">External Interrupt (EXTI) \u2013 Rotary\nEncoder<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">External interrupts (EXTI) are usually not needed unless there are tasks related to GPIO pins that require very high attention. One such task is reading a rotary encoder. Usually, a rotary encoder is not always rotated unless a change is needed. Thus, we can avoid polling its inputs in code and use an external interrupt to monitor for changes. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-63.png\" alt=\"\" class=\"wp-image-15242\" width=\"705\" height=\"430\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-63.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-63-580x354.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-63-768x468.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Most rotary encoders have two outputs. They are labelled as <em>A<\/em> and <em>B<\/em> or as <em>Data<\/em> and <em>Clock<\/em>. <em>A<\/em> and <em>B<\/em> have different phase shifts as shown in the diagram above. Let us consider a rotary encode as above. In this situation, we can attach one pin (let\u2019s say <em>A<\/em>) to an external interrupt of a C8051 and poll the other pin (let\u2019s say <em>B<\/em>) inside the interrupt for its previous and present state. In this way, we can determine if the rotary encoder is rotating in a clockwise or anticlockwise direction. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_7_bit<br> &nbsp;<br> #define ROT_ENC_DATA &nbsp; &nbsp; &nbsp; P0_0_bit<br> #define ROT_ENC_CLK &nbsp; &nbsp; &nbsp; &nbsp;P0_1_bit<br> #define ROT_ENC_SW &nbsp; &nbsp; &nbsp; &nbsp; P0_2_bit<br> &nbsp;<br> unsigned char i = 0;<br> unsigned char val = 0;<br> unsigned char past_clock_state = 0;<br> unsigned char present_clock_state = 0;<br> unsigned char data_state = 0;<br> signed int value = 0;<br> unsigned int step_size = 1;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void EXTI_0_ISR(void)<br> iv IVT_ADDR_EX0 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; present_clock_state = ROT_ENC_CLK;<br> &nbsp; &nbsp; data_state = ROT_ENC_DATA;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(present_clock_state != past_clock_state)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(data_state != present_clock_state)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value -= step_size;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value += step_size;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; past_clock_state = present_clock_state;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(value &gt; 9999)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = 9999;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void Timer_3_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> <br><br> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(ROT_ENC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(ROT_ENC_SW == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; step_size *= 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(step_size &gt; 1000)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; step_size = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TCON = 0x01;<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x07;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x81;<br> &nbsp; &nbsp; IP = 0x01;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-64.png\" alt=\"\" class=\"wp-image-15243\" width=\"705\" height=\"335\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-64.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-64-580x275.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-64-768x364.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike most other examples, this example is not clock dependent. All we need are an external interrupt and a couple of GPIO pins as inputs.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define ROT_ENC_DATA &nbsp; &nbsp; &nbsp; P0_0_bit<br> #define ROT_ENC_CLK &nbsp; &nbsp; &nbsp; &nbsp;P0_1_bit<br> #define ROT_ENC_SW &nbsp; &nbsp; &nbsp; &nbsp; P0_2_bit <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see the theory. Suppose the clock pin is attached to the interrupt pin.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-65.png\" alt=\"\" class=\"wp-image-15244\" width=\"704\" height=\"427\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-65.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-65-580x351.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-65-768x465.png 768w\" sizes=\"auto, (max-width: 704px) 100vw, 704px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As soon as an interrupt is triggered, both the data and the clock pins are polled. If there is a change in the logic state of the clock input then the state of the data pin is compared against the current state of the clock pin. This comparison tells us the direction of the rotary encoder. Based on direction a variable named&nbsp;<em>value<\/em>&nbsp;is either increment or decremented. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void EXTI_0_ISR(void)<br> iv IVT_ADDR_EX0 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; present_clock_state = ROT_ENC_CLK;<br> &nbsp; &nbsp; data_state = ROT_ENC_DATA;<br> &nbsp;<br> &nbsp; &nbsp; if(present_clock_state != past_clock_state)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(data_state != present_clock_state)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value -= step_size;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value += step_size;<br> &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; past_clock_state = present_clock_state;<br> &nbsp; &nbsp; }&nbsp; &nbsp; <br> &nbsp; &nbsp; if(value &gt; 9999)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = 0;<br> &nbsp; &nbsp; }&nbsp; &nbsp; <br> &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = 9999;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The step size of the change is determined in the main.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> if(ROT_ENC_SW == 0)<br> {<br> &nbsp;&nbsp;&nbsp; delay_ms(60);<br> &nbsp; &nbsp; while(ROT_ENC_SW == 0);<br> &nbsp; &nbsp; step_size *= 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; if(step_size &gt; 1000)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; step_size = 1;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"527\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-66.png\" alt=\"\" class=\"wp-image-15245\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-66.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-66-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-66-768x431.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - EXTI - Rotary Encoder\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/B-plZxG3h2s?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">External Interrupt (EXTI) \u2013 RFID Card Reader<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">C8051F330D microcontroller does not have pin-change interrupt capability but like many other 8051 microcontrollers, it sports two external interrupts \u2013 EXTI0 and EXTI1. In combination, these interrupts can be used for a number of applications. Here I used these interrupts for decoding a Wiegand 26 RFID card reader.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-67.png\" alt=\"\" class=\"wp-image-15247\" width=\"470\" height=\"353\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-67.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-67-580x435.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-67-768x576.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To know more about Weigand 26, RFIDs and their working principle be sure to check the following links:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/en.wikipedia.org\/wiki\/Wiegand_interface\">https:\/\/en.wikipedia.org\/wiki\/Wiegand_interface<\/a> <\/li><li><a href=\"https:\/\/getsafeandsound.com\/blog\/26-bit-wiegand-format\">https:\/\/getsafeandsound.com\/blog\/26-bit-wiegand-format<\/a> <\/li><li><a href=\"https:\/\/www.securityinfowatch.com\/access-identity\/access-control\/article\/10537302\/understanding-26bit-wiegand\">https:\/\/www.securityinfowatch.com\/access-identity\/access-control\/article\/10537302\/understanding-26bit-wiegand<\/a> <\/li><li><a href=\"https:\/\/www.techtarget.com\/iotagenda\/definition\/RFID-radio-frequency-identification\">https:\/\/www.techtarget.com\/iotagenda\/definition\/RFID-radio-frequency-identification<\/a> <\/li><li><a href=\"https:\/\/en.wikipedia.org\/wiki\/Access_control\">https:\/\/en.wikipedia.org\/wiki\/Access_control<\/a> <\/li><li><a href=\"https:\/\/en.wikipedia.org\/wiki\/Radio-frequency_identification\">https:\/\/en.wikipedia.org\/wiki\/Radio-frequency_identification<\/a> <\/li><li><\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Waveshare_RGB_LCD.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> sbit Soft_I2C_Scl at P1_7_bit;<br> sbit Soft_I2C_Sda at P1_6_bit;<br> &nbsp;<br> #define LCD_I2C_address &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x7C<br> #define RGB_I2C_address &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0xC0<br> &nbsp;<br> \/* &nbsp; &nbsp;Colour Definitions &nbsp; &nbsp;*\/<br> #define REG_RED &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x04<br> #define REG_GREEN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x03<br> #define REG_BLUE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x02<br> #define REG_MODE_1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> #define REG_MODE_2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x01<br> #define REG_OUTPUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x08<br> &nbsp;<br> \/* &nbsp; &nbsp;LCD Definitions &nbsp; &nbsp;*\/<br> #define LCD_CLEAR_DISPLAY &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x01<br> #define LCD_RETURN_HOME &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x02<br> #define LCD_ENTRY_MODE_SET &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x04<br> #define LCD_DISPLAY_CONTROL &nbsp; &nbsp; &nbsp; &nbsp; 0x08<br> #define LCD_CURSOR_SHIFT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x10<br> #define LCD_FUNCTION_SET &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x20<br> #define LCD_SET_CGRAM_ADDR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x40<br> #define LCD_SET_DDRAM_ADDR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x80<br> &nbsp;<br> \/* &nbsp; &nbsp;flags for display entry mode &nbsp; &nbsp;*\/<br> #define LCD_ENTRY_RIGHT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> #define LCD_ENTRY_LEFT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x02<br> #define LCD_ENTRY_SHIFT_INCREMENT &nbsp; 0x01<br> #define LCD_ENTRY_SHIFT_DECREMENT &nbsp; 0x00<br> &nbsp;<br> \/* &nbsp; &nbsp;flags for display on\/off control &nbsp; &nbsp;*\/<br> #define LCD_DISPLAY_ON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x04<br> #define LCD_DISPLAY_OFF &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> #define LCD_CURSOR_ON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x02<br> #define LCD_CURSOR_OFF &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> #define LCD_BLINK_ON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x01<br> #define LCD_BLINK_OFF &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> &nbsp;<br> \/* &nbsp; &nbsp;flags for display\/cursor shift &nbsp; &nbsp;*\/<br> #define LCD_DISPLAY_MOVE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x08<br> #define LCD_CURSOR_MOVE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> #define LCD_MOVE_RIGHT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x04<br> #define LCD_MOVE_LEFT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> &nbsp;<br> \/* &nbsp; &nbsp;flags for function set &nbsp; &nbsp;*\/<br> #define LCD_8_BIT_MODE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x10<br> #define LCD_4_BIT_MODE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> #define LCD_2_LINE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x08<br> #define LCD_1_LINE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> #define LCD_5x8_DOTS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> &nbsp;<br> \/* &nbsp; Data \/ Command selection &nbsp; *\/<br> #define DAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x40<br> #define CMD &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x80<br> &nbsp;<br> void RGB_LCD_init(void);<br> void I2C_bus_write(unsigned char address, unsigned char value_1, unsigned char value_2);<br> void LCD_I2C_write(unsigned char value, unsigned char mode);<br> void RGB_I2C_write(unsigned char reg, unsigned char value);<br> void set_RGB(unsigned char R, unsigned char G, unsigned char B);<br> void LCD_goto(unsigned char x_pos, unsigned char y_pos);<br> void LCD_clear_home(void);<br> void LCD_putchar(char chr);<br> void LCD_putstr(char *lcd_string); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Waveshare_RGB_LCD.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"Waveshare_RGB_LCD.h\"<br> &nbsp;<br> void RGB_LCD_init(void)<br> {<br> &nbsp; &nbsp; Soft_I2C_Init();<br> &nbsp; &nbsp; delay_ms(20);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);<br> &nbsp; &nbsp; delay_ms(5);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);<br> &nbsp; &nbsp; delay_ms(5);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);<br> &nbsp; &nbsp; delay_ms(5);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_I2C_write((LCD_FUNCTION_SET | LCD_2_LINE), CMD);<br> &nbsp; &nbsp; LCD_I2C_write((LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINK_OFF), CMD);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_I2C_write((LCD_ENTRY_MODE_SET | LCD_ENTRY_LEFT | LCD_ENTRY_SHIFT_DECREMENT), CMD);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; RGB_I2C_write(REG_MODE_1, 0x00);<br> &nbsp; &nbsp; RGB_I2C_write(REG_OUTPUT, 0xFF);<br> &nbsp; &nbsp; RGB_I2C_write(REG_MODE_2, 0x20);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; set_RGB(127, 127, 127);<br> }<br> &nbsp;<br> void I2C_bus_write(unsigned char address, unsigned char value_1, unsigned char value_2)<br> {<br> &nbsp; &nbsp; Soft_I2C_Start();<br> &nbsp; &nbsp; Soft_I2C_Write(address);<br> &nbsp; &nbsp; Soft_I2C_Write(value_1);<br> &nbsp; &nbsp; Soft_I2C_Write(value_2);<br> &nbsp; &nbsp; Soft_I2C_Stop();<br> }<br> &nbsp;<br> void LCD_I2C_write(unsigned char value, unsigned char mode)<br> {<br> &nbsp; &nbsp; I2C_bus_write(LCD_I2C_address, mode, value);<br> }<br> &nbsp;<br> void RGB_I2C_write(unsigned char reg, unsigned char value)<br> {<br> &nbsp; &nbsp; I2C_bus_write(RGB_I2C_address, reg, value);<br> }<br> &nbsp;<br> void set_RGB(unsigned char R, unsigned char G, unsigned char B)<br> {<br> &nbsp; &nbsp; RGB_I2C_write(REG_RED, R);<br> &nbsp; &nbsp; RGB_I2C_write(REG_GREEN, G);<br> &nbsp; &nbsp; RGB_I2C_write(REG_BLUE, B);<br> }<br> &nbsp;<br> void LCD_goto(unsigned char x_pos, unsigned char y_pos)<br> {<br> &nbsp; &nbsp; if(y_pos == 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; x_pos |= 0x80;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; x_pos |= 0xC0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; I2C_bus_write(LCD_I2C_address, 0x80, x_pos);<br> }<br> &nbsp;<br> void LCD_clear_home(void)<br> {<br> &nbsp; &nbsp; LCD_I2C_write(LCD_CLEAR_DISPLAY, CMD);<br> &nbsp; &nbsp; LCD_I2C_write(LCD_RETURN_HOME, CMD);<br> &nbsp; &nbsp; delay_ms(2);<br> }<br> &nbsp;<br> void LCD_putchar(char chr)<br> {<br> &nbsp; &nbsp; if((chr &gt;= 0x20) &amp;&amp; (chr &lt;= 0x7F))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_I2C_write(chr, DAT);<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void LCD_putstr(char *lcd_string)<br> {<br> &nbsp; &nbsp; do<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_putchar(*lcd_string++);<br> &nbsp; &nbsp; }while(*lcd_string != '\\0') ;<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">lcd_print_rgb.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define no_of_custom_symbol &nbsp; &nbsp; 1<br> #define array_size_per_symbol &nbsp; 8<br> #define array_size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(array_size_per_symbol * no_of_custom_symbol)<br> &nbsp;<br> void load_custom_symbol(void);<br> void print_symbol(unsigned char x_pos, unsigned char y_pos, unsigned char symbol_index);<br> void print_C(unsigned char x_pos, unsigned char y_pos, signed int value);<br> void print_I(unsigned char x_pos, unsigned char y_pos, signed long value);<br> void print_D(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char points);<br> void print_F(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">lcd_print_rgb.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"lcd_print_rgb.h\"<br> &nbsp;<br> void load_custom_symbol(void)<br> {<br> &nbsp; &nbsp; unsigned char s = 0;<br> &nbsp;<br> &nbsp; &nbsp; const unsigned char custom_symbol[array_size] =<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; 0x00, 0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; LCD_I2C_write(0x40, CMD);<br> &nbsp;<br> &nbsp; &nbsp; for(s = 0; s &lt; array_size; s++)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_I2C_write(custom_symbol[s], DAT);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; LCD_I2C_write(0x80, CMD);<br> }<br> &nbsp;<br> void print_symbol(unsigned char x_pos, unsigned char y_pos, unsigned char symbol_index)<br> {<br> &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; LCD_I2C_write(symbol_index, DAT);<br> }<br> &nbsp;<br> void print_C(unsigned char x_pos, unsigned char y_pos, signed int value)<br> {<br> &nbsp; &nbsp; &nbsp;char ch[5] = {0x20, 0x20, 0x20, 0x20, '\\0'};<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;if(value &lt; 0x00)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x2D;<br> &nbsp; &nbsp; &nbsp; &nbsp; value = -value;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x20;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;if((value &gt; 99) &amp;&amp; (value &lt;= 999))<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[1] = ((value \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[2] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[3] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;else if((value &gt; 9) &amp;&amp; (value &lt;= 99))<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[1] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[2] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;else if((value &gt;= 0) &amp;&amp; (value &lt;= 9))<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[1] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[2] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; &nbsp;LCD_putstr(ch);<br> }<br> &nbsp;<br> void print_I(unsigned char x_pos, unsigned char y_pos, signed long value)<br> {<br> &nbsp; &nbsp; char ch[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, '\\0'};<br> &nbsp;<br> &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x2D;<br> &nbsp; &nbsp; &nbsp; &nbsp; value = -value;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if(value &gt; 9999)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = ((value \/ 10000) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value % 10000)\/ 1000) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = (((value % 1000) \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; else if((value &gt; 999) &amp;&amp; (value &lt;= 9999))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = (((value % 10000)\/ 1000) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value % 1000) \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt; 99) &amp;&amp; (value &lt;= 999))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = (((value % 1000) \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt; 9) &amp;&amp; (value &lt;= 99))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; LCD_putstr(ch);<br> }<br> &nbsp;<br> void print_D(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char points)<br> {<br> &nbsp; &nbsp; char ch[5] = {0x2E, 0x20, 0x20, 0x20, 0x20};<br> &nbsp;<br> &nbsp; &nbsp; ch[1] = ((value \/ 100) + 0x30);<br> &nbsp;<br> &nbsp; &nbsp; if(points &gt; 1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value \/ 10) % 10) + 0x30);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(points &gt; 1)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; LCD_putstr(ch);<br> }<br> &nbsp;<br> void print_F(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points)<br> {<br> &nbsp; &nbsp; signed long tmp = 0x00000000;<br> &nbsp;<br> &nbsp; &nbsp; tmp = value;<br> &nbsp; &nbsp; print_I(x_pos, y_pos, tmp);<br> &nbsp; &nbsp; tmp = ((value - tmp) * 1000);<br> &nbsp;<br> &nbsp; &nbsp; if(tmp &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;tmp = -tmp;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = -value;<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_putchar(0x2D);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_putchar(0x20);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if((value &gt;= 10000) &amp;&amp; (value &lt; 100000))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 6), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt;= 1000) &amp;&amp; (value &lt; 10000))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 5), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt;= 100) &amp;&amp; (value &lt; 1000))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 4), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt;= 10) &amp;&amp; (value &lt; 100))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 3), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if(value &lt; 10)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 2), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"Waveshare_RGB_LCD.c\"<br> #include \"lcd_print_rgb.c\"<br> &nbsp;<br> unsigned char count = 0;<br> unsigned long raw_card_data = 0;<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init();<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> &nbsp;<br> void EXTI_0_ISR(void)<br> iv IVT_ADDR_EX0 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; raw_card_data &lt;&lt;= 1;<br> &nbsp; &nbsp; count++;<br> }<br> &nbsp;<br> void EXTI_1_ISR(void)<br> iv IVT_ADDR_EX1 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; raw_card_data &lt;&lt;= 1;<br> &nbsp; &nbsp; raw_card_data |= 1;<br> &nbsp; &nbsp; count++;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char facility_code = 0;<br> &nbsp; &nbsp; unsigned int card_number = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; RGB_LCD_init();<br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_goto(0, 0);<br> &nbsp; &nbsp; LCD_putstr(\"Facility:\");<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; LCD_putstr(\"Card I.D:\");<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(count &gt;= 25)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; card_number = (raw_card_data &amp; 0xFFFF);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; facility_code = (0xFF &amp; (raw_card_data &gt;&gt; 0x10));<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(12, 0, facility_code);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_I(10, 1, card_number);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raw_card_data = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TCON = 0x05;<br> }<br> &nbsp;<br> void Port_IO_Init()<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xC0;<br> &nbsp; &nbsp; P0SKIP = 0x03;<br> &nbsp; &nbsp; P1SKIP = 0xC0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x85;<br> &nbsp; &nbsp; IP = 0x05;<br> &nbsp; &nbsp; IT01CF = 0x10;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-68.png\" alt=\"\" class=\"wp-image-15248\" width=\"302\" height=\"355\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-68.png 603w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-68-552x650.png 552w\" sizes=\"auto, (max-width: 302px) 100vw, 302px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In Wiegand 26 protocol, there are 26 bits which define unique card identification (B) and facility code (A) as shown below:&nbsp;&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-69.png\" alt=\"\" class=\"wp-image-15249\" width=\"470\" height=\"99\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-69.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-69-580x122.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-69-768x162.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Bits 0 to 25 are either ones or zeroes and are defined by the D0 and D1 outputs of the Wiegand 26 RFID reader. Normally D0 and D1 remain in the high logic state. When there is a high to low transition in D0 output, a zero is read and similarly when there is such a transition in D1, a one is read. Detecting 26 such transitions results in decoding the card number.&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-70.png\" alt=\"\" class=\"wp-image-15250\" width=\"307\" height=\"137\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-70.png 614w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-70-580x259.png 580w\" sizes=\"auto, (max-width: 307px) 100vw, 307px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">External interrupts EXTI0 (P0.0) and EXTI1 (P0.1) are configured to detect high-to-low or falling edge transitions. These pins are configured as open-drain inputs.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x85;<br> &nbsp; &nbsp; IP = 0x05;<br> &nbsp; &nbsp; IT01CF = 0x10;<br> }<br> &nbsp;<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TCON = 0x05;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">EXTI0 is connected to D0 and EXTI1 is connected to D1 of the RFID reader respectively and so when interrupts are triggered bit info is processed. When EXTI0 is triggered, it means that the bit in the card code is zero. Similarly, when EXTI1 is triggered, it means that the bit in the card code is one. The variable <em>raw_card_data<\/em> contains the card info and upon every interrupt, this variable is shifted while the bit count is stored in the variable <em>count<\/em>. A <em>\u201cone\u201d<\/em> is added to the variable <em>raw_card_data<\/em> when EXTI1 is triggered. For <em>\u201czero\u201d<\/em>, nothing is needed to be done. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void EXTI_0_ISR(void)<br> iv IVT_ADDR_EX0 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; raw_card_data &lt;&lt;= 1;<br> &nbsp; &nbsp; count++;<br> }<br> &nbsp;<br> void EXTI_1_ISR(void)<br> iv IVT_ADDR_EX1 <br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; raw_card_data &lt;&lt;= 1;<br> &nbsp; &nbsp; raw_card_data |= 1;<br> &nbsp; &nbsp; count++;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the main code, the peripherals are initialized first. The bit count is checked to see if all 26 bits (0 to 25) have been read. If read so then the raw card info is processed and displayed. After displaying, bit count and raw card data variables are reset to zeroes. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char facility_code = 0;<br> &nbsp; &nbsp; unsigned int card_number = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; RGB_LCD_init();<br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_goto(0, 0);<br> &nbsp; &nbsp; LCD_putstr(\"Facility:\");<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; LCD_putstr(\"Card I.D:\");<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(count &gt;= 25)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; card_number = (raw_card_data &amp; 0xFFFF);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; facility_code = (0xFF &amp; (raw_card_data &gt;&gt; 0x10));<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(12, 0, facility_code);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_I(10, 1, card_number);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raw_card_data = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; count = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"528\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-71.png\" alt=\"\" class=\"wp-image-15251\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-71.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-71-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-71-768x432.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - EXTI - Wiegand 26 RFID Reader\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/uXVXlZ71dZk?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - EXTI - ID-12 Wiegand (WG-26) Mode\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/dmjWSAcnsFI?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">External Interrupt (EXTI) and Timer\n(TMR) \u2013 Decoding IR Remote <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Infrared (IR) remote controllers are widely\nused and cheap methods of remotely controlling appliances such as televisions,\nstereos, home theatres, etc. An IR remote transmitter sends data to an IR\nreceiver by modulating\/mixing data signals with a carrier wave of frequency\nbetween 30kHz to 40kHz. This modulation technique ensures the safety of data\nduring long-distance transmissions. At the receiving end, an IR receiver picks\nup the modulated data and demodulates it, resulting in a stream of pulses.\nThese pulses possess variable properties such as pulse widths, timing,\nposition, and phase, and they carry data. The pulse properties are governed by\na set of rules known as the protocol. By decoding the pulses according to the\nprotocol, the sent information can be retrieved.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In most microcontrollers, there is no dedicated hardware for decoding IR remote protocols. Additionally, the microcontroller receiving IR remote data does not have prior knowledge of when it will receive an IR burst. Therefore, a combination of an external interrupt and a timer coupled with some software tricks is required for decoding IR data.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-72.png\" alt=\"\" class=\"wp-image-15252\" width=\"470\" height=\"276\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-72.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-72-580x341.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-72-768x451.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">In this segment, we will explore how an external interrupt and a timer can be utilized to decode a NEC IR remote effortlessly. It is worth mentioning that this approach can be extended to decode any IR remote controller. To begin, I suggest studying the NEC IR protocol, which can be found <a href=\"https:\/\/www.sbprojects.net\/knowledge\/ir\/nec.php\">here<\/a>. For comprehensive information regarding IR remotes, <a href=\"https:\/\/www.sbprojects.net\/knowledge\/ir\/index.php\">SB-Project&#8217;s website<\/a> is highly recommended as an excellent resource.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nCode\n\n\n\n<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">SW_I2C.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define bit_shift_right(val, shift_size) &nbsp; &nbsp; (val &gt;&gt; shift_size)<br> #define bit_shift_left(val, shift_size) &nbsp; &nbsp; &nbsp;(val &lt;&lt; shift_size)<br> #define bit_mask(bit_pos) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bit_shift_left(1, bit_pos)<br> &nbsp;<br> #define bit_set(val, bit_val) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val |= bit_mask(bit_val))<br> #define bit_clr(val, bit_val) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val &amp;= (~bit_mask(bit_val)))<br> #define bit_tgl(val, bit_val) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val ^= bit_mask(bit_val))<br> #define get_bit(val, bit_val) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val &amp; bit_mask(bit_val))<br> #define get_reg(val, msk) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (val &amp; msk)<br> &nbsp;<br> #define test_if_bit_set(val, bit_val) &nbsp; &nbsp; &nbsp; (get_bit(val, bit_val) != FALSE)<br> #define test_if_bit_cleared(val, bit_val) &nbsp; (get_bit(val, bit_val) == FALSE)<br> &nbsp;<br> #define test_if_all_bits_set(val, msk) &nbsp; &nbsp; (get_reg(val, msk) == msk)<br> #define test_if_any_bit_set(val, msk) &nbsp; &nbsp; &nbsp;(get_reg(val, msk) != FALSE)<br> &nbsp;<br> #define SDA_DIR_OUT() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;do{bit_set(P1MDOUT, 6); bit_set(P0SKIP, 6);}while(0)<br> #define SDA_DIR_IN() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do{bit_clr(P1MDOUT, 6); bit_set(P0SKIP, 6);}while(0)<br> &nbsp;<br> #define SCL_DIR_OUT() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;do{bit_set(P1MDOUT, 7); bit_set(P0SKIP, 7);}while(0)<br> #define SCL_DIR_IN() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do{bit_clr(P1MDOUT, 7); bit_set(P0SKIP, 7);}while(0)<br> &nbsp;<br> #define SDA_HIGH() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bit_set(P1, 6)<br> #define SDA_LOW() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bit_clr(P1, 6)<br> &nbsp;<br> #define SCL_HIGH() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bit_set(P1, 7)<br> #define SCL_LOW() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bit_clr(P1, 7)<br> &nbsp;<br> #define SDA_IN() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; get_bit(P1, 6)<br> &nbsp;<br> #define I2C_ACK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0xFF<br> #define I2C_NACK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> &nbsp;<br> #define I2C_timeout &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1000<br> &nbsp;<br> void SW_I2C_init(void);<br> void SW_I2C_start(void);<br> void SW_I2C_stop(void);<br> unsigned char SW_I2C_read(unsigned char ack);<br> void SW_I2C_write(unsigned char value);<br> void SW_I2C_ACK_NACK(unsigned char mode);<br> unsigned char SW_I2C_wait_ACK(void); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">SW_I2C.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"SW_I2C.h\"<br> &nbsp;<br> void SW_I2C_init(void)<br> {<br> &nbsp; &nbsp; XBR1 = 0x40;<br> &nbsp; &nbsp; SDA_DIR_OUT();<br> &nbsp; &nbsp; SCL_DIR_OUT();<br> &nbsp; &nbsp; delay_us(100);<br> &nbsp; &nbsp; SDA_HIGH();<br> &nbsp; &nbsp; SCL_HIGH();<br> }<br> &nbsp;<br> void SW_I2C_start(void)<br> {<br> &nbsp; &nbsp; SDA_DIR_OUT();<br> &nbsp; &nbsp; SDA_HIGH();<br> &nbsp; &nbsp; SCL_HIGH();<br> &nbsp; &nbsp; delay_us(40);<br> &nbsp; &nbsp; SDA_LOW();<br> &nbsp; &nbsp; delay_us(40);<br> &nbsp; &nbsp; SCL_LOW();<br> }<br> &nbsp;<br> void SW_I2C_stop(void)<br> {<br> &nbsp; &nbsp; SDA_DIR_OUT();<br> &nbsp; &nbsp; SDA_LOW();<br> &nbsp; &nbsp; SCL_LOW();<br> &nbsp; &nbsp; delay_us(40);<br> &nbsp; &nbsp; SDA_HIGH();<br> &nbsp; &nbsp; SCL_HIGH();<br> &nbsp; &nbsp; delay_us(40);<br> }<br> &nbsp;<br> unsigned char SW_I2C_read(unsigned char ack)<br> {<br> &nbsp; &nbsp; unsigned char i = 8;<br> &nbsp; &nbsp; unsigned char j = 0;<br> &nbsp;<br> &nbsp; &nbsp; SDA_DIR_IN();<br> &nbsp;<br> &nbsp; &nbsp; while(i &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; SCL_LOW();<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; SCL_HIGH();<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; j &lt;&lt;= 1;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(SDA_IN() != 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(10);<br> &nbsp; &nbsp; &nbsp; &nbsp; i--;<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; switch(ack)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case I2C_ACK:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SW_I2C_ACK_NACK(I2C_ACK);;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; default:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SW_I2C_ACK_NACK(I2C_NACK);;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; return j;<br> }<br> &nbsp;<br> void SW_I2C_write(unsigned char value)<br> {<br> &nbsp; &nbsp; unsigned char i = 8;<br> &nbsp;<br> &nbsp; &nbsp; SDA_DIR_OUT();<br> &nbsp; &nbsp; SCL_LOW();<br> &nbsp;<br> &nbsp; &nbsp; while(i &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(((value &amp; 0x80) &gt;&gt; 7) != 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SDA_HIGH();<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SDA_LOW();<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; value &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; SCL_HIGH();<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; SCL_LOW();<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; i--;<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void SW_I2C_ACK_NACK(unsigned char mode)<br> {<br> &nbsp; &nbsp; SCL_LOW();<br> &nbsp; &nbsp; SDA_DIR_OUT();<br> &nbsp;<br> &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case I2C_ACK:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SDA_LOW();<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; default:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SDA_HIGH();<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; SCL_HIGH();<br> &nbsp; &nbsp; delay_us(20);<br> &nbsp; &nbsp; SCL_LOW();<br> }<br> &nbsp;<br> unsigned char SW_I2C_wait_ACK(void)<br> {<br> &nbsp; &nbsp; signed int timeout = 0;<br> &nbsp;<br> &nbsp; &nbsp; SDA_DIR_IN();<br> &nbsp;<br> &nbsp; &nbsp; SDA_HIGH();<br> &nbsp; &nbsp; delay_us(10);<br> &nbsp; &nbsp; SCL_HIGH();<br> &nbsp; &nbsp; delay_us(10);<br> &nbsp;<br> &nbsp; &nbsp; while(SDA_IN() != 0x00)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; timeout++;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(timeout &gt; I2C_timeout)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SW_I2C_stop();<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; SCL_LOW();<br> &nbsp; &nbsp; return 0;<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">PCF8574.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"SW_I2C.c\"<br> &nbsp;<br> #define PCF8574_address &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x4E<br> &nbsp;<br> #define PCF8574_write_cmd &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PCF8574_address<br> #define PCF8574_read_cmd &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(PCF8574_address | 1)<br> &nbsp;<br> void PCF8574_init(void);<br> unsigned char PCF8574_read(void);<br> void PCF8574_write(unsigned char data_byte); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">PCF8574.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"PCF8574.h\"<br> &nbsp;<br> void PCF8574_init(void)<br> {<br> &nbsp; &nbsp; SW_I2C_init();<br> &nbsp; &nbsp; delay_ms(20);<br> }<br> &nbsp;<br> unsigned char PCF8574_read(void)<br> {<br> &nbsp; &nbsp; unsigned char port_byte = 0;<br> &nbsp;<br> &nbsp; &nbsp; SW_I2C_start();<br> &nbsp; &nbsp; SW_I2C_write(PCF8574_read_cmd);<br> &nbsp; &nbsp; port_byte = SW_I2C_read(I2C_NACK);<br> &nbsp; &nbsp; SW_I2C_stop();<br> &nbsp;<br> &nbsp; &nbsp; return port_byte;<br> }<br> &nbsp;<br> void PCF8574_write(unsigned char data_byte)<br> {<br> &nbsp; &nbsp; SW_I2C_start();<br> &nbsp; &nbsp; SW_I2C_write(PCF8574_write_cmd);<br> &nbsp; &nbsp; SW_I2C_ACK_NACK(I2C_ACK);<br> &nbsp; &nbsp; SW_I2C_write(data_byte);<br> &nbsp; &nbsp; SW_I2C_ACK_NACK(I2C_ACK);<br> &nbsp; &nbsp; SW_I2C_stop();<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">LCD_2_Wire.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"PCF8574.c\"<br> &nbsp;<br> #define clear_display &nbsp; &nbsp; &nbsp; &nbsp;0x01<br> #define goto_home &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x02<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> #define cursor_direction_inc 0x06<br> #define cursor_direction_dec 0x04<br> #define display_shift &nbsp; &nbsp; &nbsp; &nbsp;0x05<br> #define display_no_shift &nbsp; &nbsp; 0x04<br> &nbsp;<br> #define display_on &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0C<br> #define display_off &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0A<br> #define cursor_on &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0A<br> #define cursor_off &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x08<br> #define blink_on &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x09<br> #define blink_off &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x08<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> #define _8_pin_interface &nbsp; &nbsp; 0x30<br> #define _4_pin_interface &nbsp; &nbsp; 0x20<br> #define _2_row_display &nbsp; &nbsp; &nbsp; 0x28<br> #define _1_row_display &nbsp; &nbsp; &nbsp; 0x20<br> #define _5x10_dots &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x60<br> #define _5x7_dots &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x20<br> &nbsp;<br> #define BL_ON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br> #define BL_OFF &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br> &nbsp;<br> #define dly &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2<br> &nbsp;<br> #define DAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br> #define CMD &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0<br> &nbsp;<br> void LCD_init(void);<br> void LCD_toggle_EN(void);<br> void LCD_send(unsigned char value, unsigned char mode); <br> void LCD_4bit_send(unsigned char lcd_data); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> void LCD_putstr(char *lcd_string);<br> void LCD_putchar(char char_data);<br> void LCD_clear_home(void);<br> void LCD_goto(unsigned char x_pos, unsigned char y_pos); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">LCD_2_Wire.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"LCD_2_Wire.h\"<br> &nbsp;<br> static unsigned char bl_state;<br> static unsigned char data_value;<br> &nbsp;<br> void LCD_init(void)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; PCF8574_init();<br> &nbsp; &nbsp; delay_ms(10);<br> &nbsp;<br> &nbsp; &nbsp; bl_state = BL_ON;<br> &nbsp; &nbsp; data_value = 0x04;<br> &nbsp; &nbsp; PCF8574_write(data_value);<br> &nbsp;<br> &nbsp; &nbsp; delay_ms(10);<br> &nbsp;<br> &nbsp; &nbsp; LCD_send(0x33, CMD);<br> &nbsp; &nbsp; LCD_send(0x32, CMD);<br> &nbsp;<br> &nbsp; &nbsp; LCD_send((_4_pin_interface | _2_row_display | _5x7_dots), CMD);<br> &nbsp; &nbsp; LCD_send((display_on | cursor_off | blink_off), CMD);<br> &nbsp; &nbsp; LCD_send((clear_display), CMD);<br> &nbsp; &nbsp; LCD_send((cursor_direction_inc | display_no_shift), CMD);<br> } &nbsp; <br> &nbsp;<br> void LCD_toggle_EN(void)<br> {<br> &nbsp; &nbsp; data_value |= 0x04;<br> &nbsp; &nbsp; PCF8574_write(data_value);<br> &nbsp; &nbsp; delay_ms(1);<br> &nbsp; &nbsp; data_value &amp;= 0xF9;<br> &nbsp; &nbsp; PCF8574_write(data_value);<br> &nbsp; &nbsp; delay_ms(1);<br> }<br> &nbsp; &nbsp;<br> &nbsp;<br> void LCD_send(unsigned char value, unsigned char mode)<br> {<br> &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;case CMD:<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data_value &amp;= 0xF4;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;case DAT:<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data_value |= 0x01;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; switch(bl_state)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;case BL_ON:<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data_value |= 0x08;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp;case BL_OFF:<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data_value &amp;= 0xF7;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; PCF8574_write(data_value);<br> &nbsp; &nbsp; LCD_4bit_send(value);<br> &nbsp; &nbsp; delay_ms(1);<br> }<br> &nbsp; &nbsp; <br> &nbsp;<br> void LCD_4bit_send(unsigned char lcd_data) &nbsp; &nbsp; &nbsp; <br> {<br> &nbsp; &nbsp; unsigned char temp = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; temp = (lcd_data &amp; 0xF0);<br> &nbsp; &nbsp; data_value &amp;= 0x0F;<br> &nbsp; &nbsp; data_value |= temp;<br> &nbsp; &nbsp; PCF8574_write(data_value);<br> &nbsp; &nbsp; LCD_toggle_EN();<br> &nbsp;<br> &nbsp; &nbsp; temp = (lcd_data &amp; 0x0F);<br> &nbsp; &nbsp; temp &lt;&lt;= 0x04;<br> &nbsp; &nbsp; data_value &amp;= 0x0F;<br> &nbsp; &nbsp; data_value |= temp;<br> &nbsp; &nbsp; PCF8574_write(data_value);<br> &nbsp; &nbsp; LCD_toggle_EN();<br> } &nbsp;<br> &nbsp;<br> void LCD_putstr(char *lcd_string)<br> {<br> &nbsp; &nbsp; do<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_putchar(*lcd_string++);<br> &nbsp; &nbsp; }while(*lcd_string != '\\0') ;<br> }<br> &nbsp;<br> void LCD_putchar(char char_data)<br> {<br> &nbsp; &nbsp; if((char_data &gt;= 0x20) &amp;&amp; (char_data &lt;= 0x7F))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_send(char_data, DAT);<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void LCD_clear_home(void)<br> {<br> &nbsp; &nbsp; LCD_send(clear_display, CMD);<br> &nbsp; &nbsp; LCD_send(goto_home, CMD);<br> }<br> &nbsp;<br> void LCD_goto(unsigned char x_pos,unsigned char y_pos)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; if(y_pos == 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_send((0x80 | x_pos), CMD);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;LCD_send((0x80 | 0x40 | x_pos), CMD);<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">lcd_print.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define no_of_custom_symbol &nbsp; &nbsp; 1<br> #define array_size_per_symbol &nbsp; 8<br> #define array_size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(array_size_per_symbol * no_of_custom_symbol)<br> &nbsp;<br> void load_custom_symbol(void);<br> void print_symbol(unsigned char x_pos, unsigned char y_pos, unsigned char symbol_index);<br> void print_C(unsigned char x_pos, unsigned char y_pos, signed int value);<br> void print_I(unsigned char x_pos, unsigned char y_pos, signed long value);<br> void print_D(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char points);<br> void print_F(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">lcd_print.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"lcd_print.h\"<br> &nbsp;<br> void load_custom_symbol(void)<br> {<br> &nbsp; &nbsp; unsigned char s = 0;<br> &nbsp;<br> &nbsp; &nbsp; const unsigned char custom_symbol[array_size] =<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; 0x00, 0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; LCD_send(0x40, CMD);<br> &nbsp;<br> &nbsp; &nbsp; for(s = 0; s &lt; array_size; s++)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LCD_send(custom_symbol[s], DAT);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; LCD_send(0x80, CMD);<br> }<br> &nbsp;<br> void print_symbol(unsigned char x_pos, unsigned char y_pos, unsigned char symbol_index)<br> {<br> &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; LCD_send(symbol_index, DAT);<br> }<br> &nbsp;<br> void print_C(unsigned char x_pos, unsigned char y_pos, signed int value)<br> {<br> &nbsp; &nbsp; &nbsp;char ch[5] = {0x20, 0x20, 0x20, 0x20, '\\0'};<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;if(value &lt; 0x00)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x2D;<br> &nbsp; &nbsp; &nbsp; &nbsp; value = -value;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x20;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;if((value &gt; 99) &amp;&amp; (value &lt;= 999))<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[1] = ((value \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[2] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[3] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;else if((value &gt; 9) &amp;&amp; (value &lt;= 99))<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[1] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[2] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;else if((value &gt;= 0) &amp;&amp; (value &lt;= 9))<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[1] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[2] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; &nbsp;LCD_putstr(ch);<br> }<br> &nbsp;<br> void print_I(unsigned char x_pos, unsigned char y_pos, signed long value)<br> {<br> &nbsp; &nbsp; char ch[7] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, '\\0'};<br> &nbsp;<br> &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x2D;<br> &nbsp; &nbsp; &nbsp; &nbsp; value = -value;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[0] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if(value &gt; 9999)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = ((value \/ 10000) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value % 10000)\/ 1000) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = (((value % 1000) \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; else if((value &gt; 999) &amp;&amp; (value &lt;= 9999))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = (((value % 10000)\/ 1000) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value % 1000) \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt; 99) &amp;&amp; (value &lt;= 999))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = (((value % 1000) \/ 100) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt; 9) &amp;&amp; (value &lt;= 99))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = (((value % 100) \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[1] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[4] = 0x20;<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[5] = 0x20;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; LCD_putstr(ch);<br> }<br> &nbsp;<br> void print_D(unsigned char x_pos, unsigned char y_pos, signed int value, unsigned char points)<br> {<br> &nbsp; &nbsp; char ch[5] = {0x2E, 0x20, 0x20, 0x20, 0x20};<br> &nbsp;<br> &nbsp; &nbsp; ch[1] = ((value \/ 100) + 0x30);<br> &nbsp;<br> &nbsp; &nbsp; if(points &gt; 1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; ch[2] = (((value \/ 10) % 10) + 0x30);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(points &gt; 1)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch[3] = ((value % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; LCD_putstr(ch);<br> }<br> &nbsp;<br> void print_F(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points)<br> {<br> &nbsp; &nbsp; signed long tmp = 0x00000000;<br> &nbsp;<br> &nbsp; &nbsp; tmp = value;<br> &nbsp; &nbsp; print_I(x_pos, y_pos, tmp);<br> &nbsp; &nbsp; tmp = ((value - tmp) * 1000);<br> &nbsp;<br> &nbsp; &nbsp; if(tmp &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;tmp = -tmp;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = -value;<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_putchar(0x2D);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_goto(x_pos, y_pos);<br> &nbsp; &nbsp; &nbsp; &nbsp; LCD_putchar(0x20);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if((value &gt;= 10000) &amp;&amp; (value &lt; 100000))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 6), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt;= 1000) &amp;&amp; (value &lt; 10000))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 5), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt;= 100) &amp;&amp; (value &lt; 1000))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 4), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((value &gt;= 10) &amp;&amp; (value &lt; 100))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 3), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if(value &lt; 10)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; print_D((x_pos + 2), y_pos, tmp, points);<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"LCD_2_Wire.c\"<br> #include \"lcd_print.c\"<br> &nbsp;<br> #define sync_high &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16000<br> #define sync_low &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10800<br> #define one_high &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2700<br> #define one_low &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1800<br> #define zero_high &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1400<br> #define zero_low &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 900<br> &nbsp;<br> bit received;<br> unsigned char bits = 0;<br> unsigned int frames[33];<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void erase_frames(void);<br> unsigned int get_timer(void);<br> void set_timer(void);<br> unsigned char decode(unsigned char start_pos, unsigned char end_pos);<br> void decode_NEC(unsigned char *addr, unsigned char *cmd);<br> &nbsp;<br> void IR_receive(void)<br> iv IVT_ADDR_EX0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; frames[bits] = get_timer();<br> &nbsp; &nbsp; bits++;<br> &nbsp; &nbsp; TR0_bit = 1;<br> &nbsp;<br> &nbsp; &nbsp; if(bits &gt;= 33)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;received = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp;TR0_bit = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; set_timer();<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char i = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned char address = 0;<br> &nbsp; &nbsp; unsigned char command = 0;<br> &nbsp;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; LCD_init();<br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_goto(0, 0);<br> &nbsp; &nbsp; LCD_putstr(\"ADR:\");<br> &nbsp; &nbsp; LCD_goto(0, 1);<br> &nbsp; &nbsp; LCD_putstr(\"CMD:\");<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;if(received)<br> &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;decode_NEC(&amp;address, &amp;command);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;print_I(12, 0, address);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;print_I(12, 1, command);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erase_frames();<br> &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TCON = 0x01;<br> &nbsp; &nbsp; TMOD = 0x01;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xC0;<br> &nbsp; &nbsp; P0SKIP = 0x01;<br> &nbsp; &nbsp; P1SKIP = 0xC0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x81;<br> &nbsp; &nbsp; IT01CF = 0x00;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void erase_frames(void)<br> {<br> &nbsp; &nbsp; &nbsp;delay_ms(90);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;for(bits = 0; bits &lt; 33; bits++)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;frames[bits] = 0x0000;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;set_timer();<br> &nbsp; &nbsp; &nbsp;received = 0;<br> &nbsp; &nbsp; &nbsp;bits = 0;<br> }<br> &nbsp;<br> unsigned int get_timer(void)<br> {<br> &nbsp; &nbsp; unsigned int time = 0;<br> &nbsp;<br> &nbsp; &nbsp; time = TH0;<br> &nbsp; &nbsp; time &lt;&lt;= 8;<br> &nbsp; &nbsp; time |= TL0;<br> &nbsp;<br> &nbsp; &nbsp; return time;<br> }<br> &nbsp;<br> void set_timer(void)<br> {<br> &nbsp; &nbsp; &nbsp;TH0 = 0;<br> &nbsp; &nbsp; &nbsp;TL0 = 0;<br> }<br> &nbsp;<br> unsigned char decode(unsigned char start_pos, unsigned char end_pos)<br> {<br> &nbsp; &nbsp; &nbsp;unsigned char value = 0;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;for(bits = start_pos; bits &lt;= end_pos; bits++)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if((frames[bits] &gt;= one_low) &amp;&amp; (frames[bits] &lt;= one_high))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value |= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else if((frames[bits] &gt;= zero_low) &amp;&amp; (frames[bits] &lt;= zero_high))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value |= 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else if((frames[bits] &gt;= sync_low) &amp;&amp; (frames[bits] &lt;= sync_high))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return 0xFF;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;return value;<br> }<br> &nbsp;<br> void decode_NEC(unsigned char *addr, unsigned char *cmd)<br> {<br> &nbsp; &nbsp; &nbsp;*addr = decode(2, 9);<br> &nbsp; &nbsp; &nbsp;*cmd = decode(18, 25);<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-73.png\" alt=\"\" class=\"wp-image-15253\" width=\"705\" height=\"462\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-73.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-73-580x380.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-73-768x503.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An NEC transmission consists of a total of 33 pulses. The initial pulse serves as the sync pulse, while the subsequent 32 pulses carry the address and command information. These 32 bits can be divided into two groups. The first group comprises 16 bits, which include the address and its inverted counterpart. The second group consists of another 16 bits, containing the command and its inverted form. Comparing the non-inverted signals with the inverted ones allows for data integrity verification.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-74.png\" alt=\"\" class=\"wp-image-15254\" width=\"554\" height=\"353\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-74.png 738w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-74-580x369.png 580w\" sizes=\"auto, (max-width: 554px) 100vw, 554px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">In the case of the NEC IR protocol, the\nreceived IR data is represented as a sequence of pulses. These pulses\ncorrespond to sync bits, ones, and zeros. Notably, the pulse widths vary within\nthis protocol. The sync bit is characterized by a high pulse lasting 9ms,\nfollowed by a low pulse of 4.5ms, resulting in a total pulse time of 13.5ms.\nRefer to the timing diagram below, where the blue pulses represent those from\nthe transmitter, and the yellow pulses represent those received by the\nreceiver. It is evident that the pulse streams are inverted, with this\ninversion occurring at the IR receiver.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the NEC IR protocol, a logic one is indicated by a pulse with a high time of 560\u03bcs and a low time of 2.25ms, resulting in a total pulse time of 2.81ms. Conversely, a logic zero is represented by a pulse with a high time of 560\u03bcs and a low time of 1.12ms, giving a total pulse time of 1.68ms.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-75.png\" alt=\"\" class=\"wp-image-15255\" width=\"656\" height=\"278\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-75.png 875w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-75-580x245.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-75-768x325.png 768w\" sizes=\"auto, (max-width: 656px) 100vw, 656px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">These timings can vary up to \u00b130% of their theoretical values due to several factors such as medium, temperature, reflections, etc. Thus, we have to define these time tolerances in our code. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define sync_high &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16000<br> #define sync_low &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10800<br> #define one_high &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2700<br> #define one_low &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1800<br> #define zero_high &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1400<br> #define zero_low &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 900 <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, the system clock is set to 12.25MHz. We have to be as precise as possible with timings because we are dealing with a time-sensitive application.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Setting up an external interrupt to detect falling edges and a timer are crucial parts in detecting IR pulse streams. This leaves the MCU free for other non-critical tasks. P0.0 is tied to external interrupt 0 (INT0) as per the code below. Timer 0 is also used.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TCON = 0x01;<br> &nbsp; &nbsp; TMOD = 0x01;<br> }<br> &nbsp;<br> ....<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x81;<br> &nbsp; &nbsp; IT01CF = 0x00;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timer 0 is operating at a speed of\napproximately 1MHz, where 1 timer tick equals 1\u00b5s. This timer is clocked with\nthe 12.25MHz system clock, which has been divided by a prescaler of 12. In this\nexample, the code utilizes the <em>&#8220;gate&#8221; <\/em>feature of this timer,\nwhich automatically starts or stops the timer. There are two possible cases\nwith the <em>gate<\/em> feature. Either the timer runs like other timers when\ninstructed to run via software, or it runs when it is coded to run and the INT0\npin is in a logic high state. The latter feature is used in this example. Note\nthat the timer overflow interrupt is not needed here. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Upon an external interrupt, the timer immediately stops due to the falling edge that triggered the interrupt and the subsequent low level at the INT0 pin. The count of the timer is captured and then stored in an array. TR0 bit is also set high so that the timer can run again.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void IR_receive(void)<br> iv IVT_ADDR_EX0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; frames[bits] = get_timer();<br> &nbsp; &nbsp; bits++;<br> &nbsp; &nbsp; TR0_bit = 1;<br> &nbsp;<br> &nbsp; &nbsp; if(bits &gt;= 33)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;received = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp;TR0_bit = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; set_timer();<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After capturing 33 pulses, the timer is fully\nstopped in order to process captured pulses.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The captured pulse times are compared against the timing extremes as mentioned earlier and sorted accordingly. This results in decoding IR data. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned char decode(unsigned char start_pos, unsigned char end_pos)<br> {<br> &nbsp; &nbsp; &nbsp;unsigned char value = 0;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;for(bits = start_pos; bits &lt;= end_pos; bits++)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if((frames[bits] &gt;= one_low) &amp;&amp; (frames[bits] &lt;= one_high))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value |= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else if((frames[bits] &gt;= zero_low) &amp;&amp; (frames[bits] &lt;= zero_high))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value |= 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else if((frames[bits] &gt;= sync_low) &amp;&amp; (frames[bits] &lt;= sync_high))<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return 0xFF;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;return value;<br> }<br> &nbsp;<br><br> void decode_NEC(unsigned char *addr, unsigned char *cmd)<br> {<br> &nbsp; &nbsp; &nbsp;*addr = decode(2, 9);<br> &nbsp; &nbsp; &nbsp;*cmd = decode(18, 25);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the main loop, after receiving and decoding an NEC frame, the address and command data are displayed on an LCD. Following this, the microcontroller is readied to receive a new NEC frame.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> if(received)<br> {<br> &nbsp;&nbsp;&nbsp; decode_NEC(&amp;address, &amp;command);<br> &nbsp; &nbsp; print_I(12, 0, address);<br> &nbsp; &nbsp; print_I(12, 1, command);<br> &nbsp; &nbsp; erase_frames();<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"525\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-76.png\" alt=\"\" class=\"wp-image-15256\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-76.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-76-580x324.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-76-768x429.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Alphanumerical LCD EXTI &amp; Timer - IR Remote Decoder\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/lv1Pp7kGRrE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Serial Communication (UART) \u2013\nHC-SR04 SONAR Reader<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Serial communication via UART peripheral is\nthe most widely used communication method between computers and\nmicrocontrollers, portable devices and so on. Many sensors and communication\ndevices such as GSM modems, GPS receivers, RF modules, etc employ UART-based\ncommunication to transact data with host devices. UART peripheral is also the\nbackbone of several other communications such as MODBUS, LIN, IrDA and so on. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Only a pair of wires along with a ground wire are needed to establish communication between devices. Unless there is a requirement for longer range or voltage-level shifting, no additional hardware is needed to be able to use this peripheral. The following diagram below shows a simplified UART bus.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-77.png\" alt=\"\" class=\"wp-image-15258\" width=\"470\" height=\"129\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-77.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-77-580x159.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-77-768x211.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To learn more about UART visit the\nfollowing link: <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/learn.mikroe.com\/uart-serial-communication\">https:\/\/learn.mikroe.com\/uart-serial-communication<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To demonstrate the use of UART peripheral, I used a HC-SR04-to-serial converter. It is also known as a digital tape. This device measures and shows the distance between it and an object facing it using a HC-SR04 ultrasonic SONAR sensor. The extra feature of this device is the measurement output via serial peripherals.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-78.png\" alt=\"\" class=\"wp-image-15259\" width=\"470\" height=\"192\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-78.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-78-580x237.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-78-768x314.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT P1_6_bit<br> #define &nbsp;LED_CLK P1_5_bit<br> #define &nbsp;LED_LATCH P1_7_bit<br> &nbsp;<br> unsigned int d = 0;<br> unsigned char cnt = 0;<br> unsigned char value = 0;<br> char rx_buffer[18];<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void UART0_ISR(void)<br> iv IVT_ADDR_ES0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; rx_buffer[cnt++] = UART_Read();<br> &nbsp; &nbsp; RI0_bit = 0;<br> }<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = (d \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = ((d % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = ((d % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = (d % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if(d &gt;= 40000)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; segment_write(11, i);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; segment_write(value, i);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; &nbsp;unsigned char i = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned char j = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned char k = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned char l = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned int multiplier = 1;<br> &nbsp; &nbsp; &nbsp;unsigned int range = 0x0000;<br> &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp;Init_Device();<br> &nbsp; &nbsp; &nbsp;UART1_Init(9600);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;while(1)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(cnt &gt;= 18)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = 0; i &lt; 18; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(rx_buffer[i] == 'D')<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j = i;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j += 2;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = j; i &lt; 18; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(rx_buffer[i] == ' ')<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;k = i;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;range = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;multiplier = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;l = ((k - j) - 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = 0; i &lt; l; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;multiplier *= 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = j; i &lt; k; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range += ((rx_buffer[i] - 0x30) * multiplier);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; multiplier \/= 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d = range;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cnt = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp;};<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;TX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;RX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x30;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x01;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x90;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 0x08;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-79.png\" alt=\"\" class=\"wp-image-15260\" width=\"705\" height=\"356\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-79.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-79-580x292.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-79-768x387.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To simplify things, the MikroC compiler\u2019s UART library is used in this example. The rest of the setup is just like all other examples. Thus, we can focus on data processing and working of the UART peripheral. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> Init_Device();<br> UART1_Init(9600); <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The digital tape provides distance in the following string format at a baud rate of 9600 bps:<\/p>\n\n\n\n<blockquote style=\"text-align:center\" class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><strong>D:XXX\\r\\n<\/strong><\/p><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Thus, the UART of C8051F330 has to read 8\nbytes (7 actually and a null character) of data. Interrupt-based data\nacquisition is used because this method not only frees up the main loop but\nalso addresses the fact that no one knows when and from which part of data\nwould be transmitted and received. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, a global data buffer is needed that would store any data received by the UART reception interrupt. This buffer should be larger than the actual number of data bytes that would be received and this is so to accommodate at least two successive transmissions from the tape. At every interrupt, the UART is read and the buffer is filled sequentially.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> char rx_buffer[18];<br> &nbsp;<br> ....<br> &nbsp;<br> void UART0_ISR(void)<br> iv IVT_ADDR_ES0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; rx_buffer[cnt++] = UART_Read();<br> &nbsp; &nbsp; RI0_bit = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the buffer inside the interrupt is full, the code starts searching for the string of characters as per the mentioned format the tape is supposed to send. Once the character \u201c<em>D<\/em>\u201d is found, the code then searches for numeric characters before null character. The numeric characters are then converted to numbers and the distance is computed and shown on the display. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; &nbsp;unsigned char i = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned char j = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned char k = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned char l = 0x00;<br> &nbsp; &nbsp; &nbsp;unsigned int multiplier = 1;<br> &nbsp; &nbsp; &nbsp;unsigned int range = 0x0000;<br> &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp;Init_Device();<br> &nbsp; &nbsp; &nbsp;UART1_Init(9600);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;while(1)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(cnt &gt;= 18)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = 0; i &lt; 18; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(rx_buffer[i] == 'D')<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j = i;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j += 2;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = j; i &lt; 18; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(rx_buffer[i] == ' ')<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;k = i;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;range = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;multiplier = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;l = ((k - j) - 1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = 0; i &lt; l; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;multiplier *= 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i = j; i &lt; k; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range += ((rx_buffer[i] - 0x30) * multiplier);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; multiplier \/= 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d = range;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cnt = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(40);<br> &nbsp; &nbsp; &nbsp;};<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"525\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-80.png\" alt=\"\" class=\"wp-image-15261\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-80.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-80-580x324.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-80-768x429.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"533\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-81.png\" alt=\"\" class=\"wp-image-15262\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-81.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-81-580x329.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-81-768x436.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Serial Communication (UART) - HC-SR04 SONAR Reader\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/eZXi5qdfD3g?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">MODBUS \u2013 ToF200 Distance Sensor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MODBUS RTU protocol is the industry standard for reliable serial communication among devices via RS232, RS485, etc. In MODBUS RTU, data from and to a device is sent and received in a specific packet format that encapsulates ID, function code, location address, number of bytes, data and a CRC field. If one or some fields of this encapsulation is wrong then the entire frame is discarded as garbage. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-82.png\" alt=\"\" class=\"wp-image-15264\" width=\"705\" height=\"427\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-82.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-82-580x351.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-82-768x465.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Shown above are two common\ntypes of MODBUS hardware implementation. The first one utilizes RS485 as a medium\nfor longer range while the latter is mostly seen in short-range and onboard\ncomponents. The basic MODBUS protocol is the same in both cases except for the\nmedium.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MODBUS is itself\na large topic to discuss here and so to know more about MODBUS, visit these\nlinks:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/en.wikipedia.org\/wiki\/Modbus\">https:\/\/en.wikipedia.org\/wiki\/Modbus<\/a>\n<\/li><li><a href=\"https:\/\/modbus.org\/docs\/PI_MBUS_300.pdf\">https:\/\/modbus.org\/docs\/PI_MBUS_300.pdf<\/a>\n<\/li><li><a href=\"https:\/\/modbus.org\/docs\/Modbus_Application_Protocol_V1_1b.pdf\">https:\/\/modbus.org\/docs\/Modbus_Application_Protocol_V1_1b.pdf<\/a>\n<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">ToF200.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define ToF200_TX_data_packet_size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8<br> #define ToF200_RX_data_packet_size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;16<br> &nbsp;<br> #define ToF200_slave_default_ID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x01<br> &nbsp;<br> \/\/registers<br> #define ToF200_special_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0001<br> #define ToF200_slave_ID_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0002<br> #define ToF200_baud_rate_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0003<br> #define ToF200_range_precision_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0004<br> #define ToF200_output_control_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0005<br> #define ToF200_load_calibration_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0006<br> #define ToF200_offset_correction_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0007<br> #define ToF200_xtalk_correction_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0008<br> #define ToF200_i2c_enable_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0009<br> #define ToF200_measurement_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0010<br> #define ToF200_offset_calibration_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0020<br> #define ToF200_xtalk_calibration_register &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0021<br> &nbsp;<br> \/\/parameters<br> #define ToF200_restore_default &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0xAA55<br> #define ToF200_reboot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x1000<br> #define ToF200_comm_test &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0000<br> &nbsp;<br> #define ToF200_baud_rate_115200 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0000<br> #define ToF200_baud_rate_38400 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0001<br> #define ToF200_baud_rate_9600 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0002<br> &nbsp;<br> #define ToF200_high_precision_1200mm &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0001<br> #define ToF200_medium_precision_2000mm &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0002<br> #define ToF200_low_precision_1200mm &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0003<br> &nbsp;<br> #define ToF200_do_not_load_calibration &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x0000<br> #define ToF200_load_calibration &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0001<br> &nbsp;<br> #define ToF200_i2c_not_prohibited &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0000<br> #define ToF200_i2c_prohibited &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0001<br> &nbsp;<br> \/\/other constant parameters<br> #define ToF200_default_max_distance &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2000<br> &nbsp;<br> #define MODBUS_read_holding_registers_function_code &nbsp; 0x03<br> #define MODBUS_write_single_register_function_code &nbsp; &nbsp;0x06<br> &nbsp;<br> unsigned char cnt;<br> unsigned char rx_buffer[ToF200_RX_data_packet_size];<br> &nbsp;<br> unsigned int make_word(unsigned char HB, unsigned char LB);<br> void get_HB_LB(unsigned int value, unsigned char *HB, unsigned char *LB);<br> unsigned int MODBUS_RTU_CRC16(unsigned char *data_input, unsigned char data_length);<br> void flush_RX_buffer(void);<br> void MODBUS_TX(unsigned char slave_ID, unsigned char function_code, unsigned char reg, unsigned char value);<br> unsigned int ToF_get_range(void); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">ToF200.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"ToF200.h\"<br> &nbsp;<br> unsigned int make_word(unsigned char HB, unsigned char LB)<br> {<br> &nbsp; &nbsp; unsigned int tmp = 0;<br> &nbsp;<br> &nbsp; &nbsp; tmp = HB;<br> &nbsp; &nbsp; tmp &lt;&lt;= 8;<br> &nbsp; &nbsp; tmp |= LB;<br> &nbsp;<br> &nbsp; &nbsp; return tmp;<br> }<br> &nbsp;<br> void get_HB_LB(unsigned int value, unsigned char *HB, unsigned char *LB)<br> {<br> &nbsp; &nbsp; *LB = (unsigned char)(value &amp; 0x00FF);<br> &nbsp; &nbsp; *HB = (unsigned char)((value &amp; 0xFF00) &gt;&gt; 8);<br> }<br> &nbsp;<br> unsigned int MODBUS_RTU_CRC16(unsigned char *data_input, unsigned char data_length)<br> {<br> &nbsp; &nbsp; unsigned char n = 8;<br> &nbsp; &nbsp; unsigned char s = 0;<br> &nbsp; &nbsp; unsigned int CRC_word = 0xFFFF;<br> &nbsp;<br> &nbsp; &nbsp; for(s = 0; s &lt; data_length; s++)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; CRC_word ^= ((unsigned int)data_input[s]);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; n = 8;<br> &nbsp; &nbsp; &nbsp; while(n &gt; 0)<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((CRC_word &amp; 0x0001) == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_word &gt;&gt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_word &gt;&gt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_word ^= 0xA001;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; n--;<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; return CRC_word;<br> }<br> &nbsp;<br> void flush_RX_buffer(void)<br> {<br> &nbsp; &nbsp; signed char s = (ToF200_TX_data_packet_size - 1);<br> &nbsp;<br> &nbsp; &nbsp; while(s &gt; -1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; rx_buffer[s] = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; s--;<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void MODBUS_TX(unsigned char slave_ID, unsigned char function_code, unsigned char reg, unsigned char value)<br> {<br> &nbsp; &nbsp; unsigned char i &nbsp;= 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned int temp = 0x0000;<br> &nbsp;<br> &nbsp; &nbsp; unsigned char tx_buffer[ToF200_TX_data_packet_size];<br> &nbsp;<br> &nbsp; &nbsp; tx_buffer[0x00] = slave_ID;<br> &nbsp; &nbsp; tx_buffer[0x01] = function_code;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; get_HB_LB(reg, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; tx_buffer[0x02] = hb;<br> &nbsp; &nbsp; tx_buffer[0x03] = lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; tx_buffer[0x04] = hb;<br> &nbsp; &nbsp; tx_buffer[0x05] = lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; temp = MODBUS_RTU_CRC16(tx_buffer, 6);<br> &nbsp; &nbsp; get_HB_LB(temp, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; tx_buffer[0x06] = lb;<br> &nbsp; &nbsp; tx_buffer[0x07] = hb;<br> &nbsp;<br> &nbsp; &nbsp; flush_RX_buffer();<br> &nbsp;<br> &nbsp; &nbsp; for(i = 0; i &lt; ToF200_TX_data_packet_size; i++)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; UART_Write(tx_buffer[i]);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; cnt = 0x00;<br> &nbsp; &nbsp; delay_ms(40);<br> }<br> &nbsp;<br> unsigned int ToF_get_range(void)<br> {<br> &nbsp; &nbsp; unsigned int CRC_1 = 0x0000;<br> &nbsp; &nbsp; unsigned int CRC_2 = 0x0000;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned int distance = 5000;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; MODBUS_TX(ToF200_slave_default_ID, <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MODBUS_read_holding_registers_function_code, <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ToF200_measurement_register,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0001);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; if(rx_buffer[0x00] == ToF200_slave_default_ID)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(rx_buffer[0x01] == MODBUS_read_holding_registers_function_code)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(rx_buffer[0x02] == 0x02)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_1 = MODBUS_RTU_CRC16(rx_buffer, 5);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_2 = make_word(rx_buffer[0x06], rx_buffer[0x05]);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(CRC_1 == CRC_2)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distance = make_word(rx_buffer[0x03], rx_buffer[0x04]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(distance &gt; ToF200_default_max_distance)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distance = 40000;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distance = 40000;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return distance;<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"ToF200.c\"<br> &nbsp;<br> #define LED_DOUT P1_6_bit<br> #define &nbsp;LED_CLK P1_5_bit<br> #define &nbsp;LED_LATCH P1_7_bit<br> &nbsp;<br> unsigned int d = 0;<br> unsigned char i = 0;<br> unsigned char value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void UART0_ISR(void)<br> iv IVT_ADDR_ES0 <br> ilevel 0<br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; rx_buffer[cnt++] = UART_Read();<br> &nbsp; &nbsp; RI0_bit = 0;<br> }<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = (d \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = ((d % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = ((d % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = (d % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; if(d &gt;= 40000)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; segment_write(11, i);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; segment_write(value, i);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; &nbsp;Init_Device();<br> &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp;while(1)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d = ((float)ToF_get_range());<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(400);<br> &nbsp; &nbsp; &nbsp;};<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;TX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;RX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x30;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x01;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x90;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> &nbsp; &nbsp; UART1_Init(115200);<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 0x08;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-83.png\" alt=\"\" class=\"wp-image-15265\" width=\"705\" height=\"343\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-83.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-83-580x282.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-83-768x373.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, a ToF200 IR rangefinder sensor is used. This sensor communicates via MODBUS RTU frames over UART medium. Therefore, we would need to set up the UART peripheral and UART reception interrupt.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;TX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;RX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x30;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x01;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x90;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> &nbsp; &nbsp; UART1_Init(115200);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <em>ToF200.h<\/em> header file describes the functions, registers and parameter values. The codes in <em>ToF200.c<\/em> source file is what we need to understand. The following functions are typical data manipulation functions. Of these, the <em>MODBUS_RTU_CRC16<\/em> function is a bit critical because it generates CRC value when MODBUS frame data is passed to it. This function has been described by MODBUS documentation and so we can simply avoid trying to recreate it on our own. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned int make_word(unsigned char HB, unsigned char LB);<br> void get_HB_LB(unsigned int value, unsigned char *HB, unsigned char *LB);<br> unsigned int MODBUS_RTU_CRC16(unsigned char *data_input, unsigned char data_length);<br> void flush_RX_buffer(void); <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The sensor will send out data when it is asked to return distance. To do so, we have to use the following function. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void MODBUS_TX(unsigned char slave_ID, unsigned char function_code, unsigned char reg, unsigned char value)<br> {<br> &nbsp; &nbsp; unsigned char i &nbsp;= 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned int temp = 0x0000;<br> &nbsp;<br> &nbsp; &nbsp; unsigned char tx_buffer[ToF200_TX_data_packet_size];<br> &nbsp;<br> &nbsp; &nbsp; tx_buffer[0x00] = slave_ID;<br> &nbsp; &nbsp; tx_buffer[0x01] = function_code;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; get_HB_LB(reg, &amp;hb, &amp;lb);&nbsp; &nbsp; <br> &nbsp; &nbsp; tx_buffer[0x02] = hb;<br> &nbsp; &nbsp; tx_buffer[0x03] = lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; tx_buffer[0x04] = hb;<br> &nbsp; &nbsp; tx_buffer[0x05] = lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; temp = MODBUS_RTU_CRC16(tx_buffer, 6);<br> &nbsp; &nbsp; get_HB_LB(temp, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; tx_buffer[0x06] = lb;<br> &nbsp; &nbsp; tx_buffer[0x07] = hb;<br> &nbsp;<br> &nbsp; &nbsp; flush_RX_buffer();<br> &nbsp;<br> &nbsp; &nbsp; for(i = 0; i &lt; ToF200_TX_data_packet_size; i++)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; UART_Write(tx_buffer[i]);<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; cnt = 0x00;<br> &nbsp; &nbsp; delay_ms(40);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">What this function does is simply transmit data from our C8051F330D microcontroller to the ToF200 sensor in the following MODBUS RTU frame format. The first byte is the slave ID followed by the holding register read function, the register to be accessed, data length and CRC high and low bytes computed from these values.&nbsp; Before sending these bytes, the reception buffer array, <em>rx_buffer<\/em> which would hold the data from the sensor is flushed or cleared of any previous value and the byte counter variable <em>cnt<\/em> is set to zero.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-84.png\" alt=\"\" class=\"wp-image-15266\" width=\"705\" height=\"110\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-84.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-84-580x91.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-84-768x120.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The data received from the sensor is read using the UART RX interrupt. Whenever a new byte is received by the microcontroller\u2019s UART RX pin, an interrupt is triggered. The received bytes are stored in a buffer array. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void UART0_ISR(void)<br> iv IVT_ADDR_ES0 <br> ilevel 0<br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; rx_buffer[cnt++] = UART_Read();<br> &nbsp; &nbsp; RI0_bit = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The received data buffer array is then processed to compute distance. The following function returns the range of objects detected by the sensor. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned int ToF_get_range(void)<br> {<br> &nbsp; &nbsp; unsigned int CRC_1 = 0x0000;<br> &nbsp; &nbsp; unsigned int CRC_2 = 0x0000;&nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned int distance = 5000;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; MODBUS_TX(ToF200_slave_default_ID, <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MODBUS_read_holding_registers_function_code, <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ToF200_measurement_register,<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0001);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; if(rx_buffer[0x00] == ToF200_slave_default_ID)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(rx_buffer[0x01] == MODBUS_read_holding_registers_function_code)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(rx_buffer[0x02] == 0x02)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_1 = MODBUS_RTU_CRC16(rx_buffer, 5);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CRC_2 = make_word(rx_buffer[0x06], rx_buffer[0x05]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(CRC_1 == CRC_2)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distance = make_word(rx_buffer[0x03], rx_buffer[0x04]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(distance &gt; ToF200_default_max_distance)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distance = 40000;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; distance = 40000;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return distance;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, the function transmits commands to the sensor to return range data. After that, the sensor begins transmitting range data and thus, UART RX interrupt triggers. Data is likely to be received in the following frame format. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-85.png\" alt=\"\" class=\"wp-image-15267\" width=\"705\" height=\"107\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-85.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-85-580x88.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-85-768x116.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the <em>ToF_get_range<\/em>\nfunction, slave ID, function code and the number of returned bytes are checked\nagainst what they should be. If these are okay, the received CRC value is\nchecked against the computed CRC value. If both of these values match then the\ndistance value is read and returned. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the main loop, the distance is read every 400ms and the read data is shown on the onboard seven-segment LED display.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; &nbsp;Init_Device();<br> &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp;while(1)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d = ((float)ToF_get_range());<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(400);<br> &nbsp; &nbsp; &nbsp;};<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"531\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-86.png\" alt=\"\" class=\"wp-image-15268\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-86.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-86-580x328.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-86-768x434.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - MODBUS (UART) - ToF200H Distance Sensor\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/fUFDKg7su7A?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">SPI \u2013 MAX31865 PT100 RTD Amplifier<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Serial Peripheral\nInterface (SPI) communication is a multi-wire high-speed short-distance\nsynchronous communication method. Three (half-duplex) or four (full-duplex)\npins is all that are needed to establish communication between a host (master)\nand a slave. These pins are as follows: &nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong><em>Master-In-Slave-Out (MIS0)<\/em><\/strong><strong><em> <\/em><\/strong>connected to <strong><em>Slave-Data-Out (SDO)<\/em><\/strong>. <\/li><li><strong><em>Master-Out-Slave-In (MOSI) <\/em><\/strong>connected\nto <strong><em>Slave-Data-In (SDI)<\/em><\/strong>. <\/li><li><strong><em>Serial Clock (SCLK)<\/em><\/strong><strong><em> <\/em><\/strong>connected to <strong><em>Slave Clock (SCK)<\/em><\/strong>. <\/li><li><strong><em>Slave Select (SS)<\/em><\/strong><strong><em> <\/em><\/strong>connected to <strong><em>Chip Select (CS)<\/em><\/strong>. <\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-87.png\" alt=\"\" class=\"wp-image-15269\" width=\"470\" height=\"135\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-87.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-87-580x166.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-87-768x220.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Multiple slaves can be present in a common SPI bus but their chip-select pins have to be different. This is where SPI communication falls behind UART and I2C communications. However, the raw speed advantage makes SPI the number one choice for displays, flash memories, sensors, etc.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-88.png\" alt=\"\" class=\"wp-image-15270\" width=\"470\" height=\"157\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-88.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-88-580x194.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-88-768x257.png 768w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-88-420x140.png 420w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To know more about SPI bus, the\nfollowing links are very informative: <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/learn.mikroe.com\/spi-bus\">https:\/\/learn.mikroe.com\/spi-bus<\/a> &nbsp;&nbsp;<\/li><li><a href=\"https:\/\/learn.sparkfun.com\/tutorials\/serial-peripheral-interface-spi\">https:\/\/learn.sparkfun.com\/tutorials\/serial-peripheral-interface-spi<\/a><\/li><li><a href=\"http:\/\/ww1.microchip.com\/downloads\/en\/devicedoc\/spi.pdf\">http:\/\/ww1.microchip.com\/downloads\/en\/devicedoc\/spi.pdf<\/a><\/li><li><a href=\"http:\/\/tronixstuff.com\/2011\/05\/13\/tutorial-arduino-and-the-spi-bus\">http:\/\/tronixstuff.com\/2011\/05\/13\/tutorial-arduino-and-the-spi-bus<\/a><\/li><li><a href=\"https:\/\/www.analog.com\/en\/analog-dialogue\/articles\/introduction-to-spi-interface.html\">https:\/\/www.analog.com\/en\/analog-dialogue\/articles\/introduction-to-spi-interface.html<\/a><\/li><li><a href=\"http:\/\/www.circuitbasics.com\/basics-of-the-spi-communication-protocol\">http:\/\/www.circuitbasics.com\/basics-of-the-spi-communication-protocol<\/a> &nbsp;<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">MAX31865.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define MAX31865_CONFIG_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> #define MAX31865_RTD_MSB_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x01<br> #define MAX31865_RTD_LSB_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x02<br> #define MAX31865_HFAULT_MSB_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x03<br> #define MAX31865_HFAULT_LSB_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x04<br> #define MAX31865_LFAULT_MSB_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x05<br> #define MAX31865_LFAULT_LSB_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x06<br> #define MAX31865_FAULT_STATUS_REG &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x07<br> &nbsp;<br> \/* Configuration Definitions *\/<br> #define MAX31865_CONFIG_BIAS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x80<br> #define MAX31865_CONFIG_MODE_AUTO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x40<br> #define MAX31865_CONFIG_MODE_OFF &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> #define MAX31865_CONFIG_1SHOT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x20<br> #define MAX31865_CONFIG_3_WIRE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x10<br> #define MAX31865_CONFIG_24_WIRE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> #define MAX31865_CONFIG_FAULT_STATUS &nbsp; &nbsp; &nbsp; &nbsp; 0x02<br> #define MAX31865_CONFIG_FILTER_50Hz &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x01<br> #define MAX31865_CONFIG_FILTER_60Hz &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x00<br> &nbsp;<br> \/* Fault Definitions *\/<br> #define MAX31865_FAULT_HIGH_THRESHOLD &nbsp; &nbsp; &nbsp; &nbsp;0x80<br> #define MAX31865_FAULT_LOW_THRESHOLD &nbsp; &nbsp; &nbsp; &nbsp; 0x40<br> #define MAX31865_FAULT_REF_IN_LOW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x20<br> #define MAX31865_FAULT_REF_IN_HIGH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x10<br> #define MAX31865_FAULT_RTD_IN_LOW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x08<br> #define MAX31865_FAULT_OV_UV &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x04<br> &nbsp;<br> #define MAX31865_RTD_A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0.00390803<br> #define MAX31865_RTD_B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -0.000000577<br> #define MAX31865_Reference_Resistance &nbsp; &nbsp; &nbsp; &nbsp;430.0<br> #define MAX31865_RTD_Nominal_Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100.0 \/\/ for PT100<br> &nbsp;<br> #define MAX31865_CS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P0_3_bit<br> &nbsp;<br> void MAX31865_init(void);<br> unsigned char MAX31865_read_byte(unsigned char address);<br> unsigned int MAX31865_read_word(unsigned char address);<br> void MAX31865_write_byte(unsigned char address, unsigned char value);<br> void MAX31865_write_word(unsigned char address, unsigned char lb, unsigned char hb);<br> unsigned int MAX31865_get_RTD(void);<br> signed int MAX31865_get_temperature(void); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">MAX31865.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"MAX31865.h\"<br> &nbsp;<br> void MAX31865_init(void)<br> {<br> &nbsp; &nbsp; SPI1_Init_Advanced(1000000, _SPI_CLK_IDLE_LO | _SPI_CLK_ACTIVE_2_IDLE | _SPI_MASTER);<br> &nbsp; &nbsp; delay_ms(10);<br> &nbsp;<br> &nbsp; &nbsp; MAX31865_CS = 1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; MAX31865_write_byte(MAX31865_CONFIG_REG, \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_BIAS | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_MODE_AUTO | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_3_WIRE | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_FAULT_STATUS | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_FILTER_50Hz);<br> }<br> &nbsp;<br> unsigned char MAX31865_read_byte(unsigned char address)<br> {<br> &nbsp; &nbsp; unsigned char retval = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; MAX31865_CS = 0;<br> &nbsp; &nbsp; SPI_Write(address &amp; 0x7F);<br> &nbsp; &nbsp; retval = SPI_Read(0x00);<br> &nbsp; &nbsp; MAX31865_CS = 1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return retval;<br> }<br> &nbsp;<br> unsigned int MAX31865_read_word(unsigned char address)<br> {<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned int retval = 0x0000;<br> &nbsp;<br> &nbsp; &nbsp; hb = MAX31865_read_byte(address);<br> &nbsp; &nbsp; lb = MAX31865_read_byte(address + 1);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; retval = hb;<br> &nbsp; &nbsp; retval &lt;&lt;= 0x08;<br> &nbsp; &nbsp; retval |= lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return retval;<br> }<br> &nbsp;<br> void MAX31865_write_byte(unsigned char address, unsigned char value)<br> {<br> &nbsp; &nbsp; MAX31865_CS = 0;<br> &nbsp; &nbsp; SPI_Write(address | 0x80);<br> &nbsp; &nbsp; SPI_Write(value);<br> &nbsp; &nbsp; MAX31865_CS = 1;<br> }<br> &nbsp;<br> void MAX31865_write_word(unsigned char address, unsigned char lb, unsigned char hb)<br> {<br> &nbsp; &nbsp; MAX31865_write_byte(address, hb);<br> &nbsp; &nbsp; MAX31865_write_byte((address + 1), lb);<br> }<br> &nbsp;<br> unsigned int MAX31865_get_RTD(void)<br> {<br> &nbsp; unsigned int rtd_value = 0x00;<br> &nbsp; <br> &nbsp; rtd_value = MAX31865_read_word(MAX31865_RTD_MSB_REG);<br> &nbsp; rtd_value &gt;&gt;= 1;<br> &nbsp; <br> &nbsp; return rtd_value;<br> }<br> &nbsp;<br> signed int MAX31865_get_temperature(void)<br> {<br> &nbsp; &nbsp; float rt = 0.0;<br> &nbsp; &nbsp; signed int t_value = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; t_value = MAX31865_get_RTD();<br> &nbsp; &nbsp; rt = (MAX31865_Reference_Resistance * t_value);<br> &nbsp; &nbsp; rt \/= 32768.0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; rt \/= MAX31865_RTD_Nominal_Value;<br> &nbsp; &nbsp; rt = (rt - 1.0);<br> &nbsp; &nbsp; t_value = (rt \/ MAX31865_RTD_A);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return t_value;<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"MAX31865.c\"<br> &nbsp;<br> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; P1_7_bit<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x9C, \/\/ degree<br> &nbsp; 0xC6 &nbsp;\/\/ C<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void SPI_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_ISR()<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 11;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; MAX31865_init();<br> &nbsp;<br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = MAX31865_get_temperature();<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(600);<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void SPI_Init(void)<br> {<br> &nbsp; &nbsp; SPI0CFG = 0x40;<br> &nbsp; &nbsp; SPI0CN = 0x01;<br> &nbsp; &nbsp; SPI0CKR = 0x05;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;SCK &nbsp;(SPI0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;MISO (SPI0), Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;MOSI (SPI0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x0D;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x08;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x02;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; SPI_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-89.png\" alt=\"\" class=\"wp-image-15271\" width=\"705\" height=\"328\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-89.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-89-580x270.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-89-768x357.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">MAX31865 is a PT100-to-digital converter. It converts resistance data from a PT100 RTD sensor to digital temperature data that is sent to a host microcontroller via an SPI bus.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, the system clock is set to 12.25MHz.  <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pins P0.0 to P0.3 are set as SPI pins in the crossbar. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;SCK &nbsp;(SPI0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;MISO (SPI0), Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;MOSI (SPI0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x0D;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x08;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x02;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">MAX31865 header file contains all the\nconstants and function prototypes that would be eventually needed in the\nMAX31865 source file.&nbsp;&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s look at what\u2019s inside the source file. The first thing in the MAX31865 source file is the initialization of the MAX31865 along with the initialization of the SPI peripheral of the host C8051F330. The built-in SPI library of MikroC is used to do the peripheral hardware initialization.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void MAX31865_init(void)<br> {<br> &nbsp; &nbsp; SPI1_Init_Advanced(1000000, _SPI_CLK_IDLE_LO | _SPI_CLK_ACTIVE_2_IDLE | _SPI_MASTER);<br> &nbsp; &nbsp; delay_ms(10);<br> &nbsp;<br> &nbsp; &nbsp; MAX31865_CS = 1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; MAX31865_write_byte(MAX31865_CONFIG_REG, \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_BIAS | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_MODE_AUTO | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_3_WIRE | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_FAULT_STATUS | \\<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MAX31865_CONFIG_FILTER_50Hz);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The SPI protocol defines four different modes of operation, also known as SPI bus modes. The modes differ in terms of the clock polarity and clock phase and the timing of the data signals. The four SPI bus modes are as follows:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"417\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-90.png\" alt=\"\" class=\"wp-image-15272\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-90.png 620w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-90-580x390.png 580w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As per the datasheet of MAX31865, the chip supports both Mode 1 and Mode 3 SPI bus modes and so, here, Mode 1 is used. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-91.png\" alt=\"\" class=\"wp-image-15273\" width=\"470\" height=\"180\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-91.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-91-580x222.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-91-768x294.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The next important functions are the SPI byte read and write functions. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void MAX31865_write_byte(unsigned char address, unsigned char value)<br> {<br> &nbsp; &nbsp; MAX31865_CS = 0;<br> &nbsp; &nbsp; SPI_Write(address | 0x80);<br> &nbsp; &nbsp; SPI_Write(value);<br> &nbsp; &nbsp; MAX31865_CS = 1;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The write function is very simple. Writing to the chip is initiated by holding the chip\/slave select pin low and sending the address and data bytes, i.e., two bytes are sent. Once the transaction is completed, the chip select pin is held high. During this process, no data reading is done. The polarity and phase of SPI signals are maintained automatically. The timing diagram for the SPI write is shown below and it clearly shows what has been described.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-92.png\" alt=\"\" class=\"wp-image-15274\" width=\"470\" height=\"113\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-92.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-92-580x139.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-92-768x184.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Reading the chip is similar to write process. The only difference that exists is the reading process itself. During an SPI bus read, a dummy byte is sent to the chip. The following function is for SPI byte read:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned char MAX31865_read_byte(unsigned char address)<br> {<br> &nbsp; &nbsp; unsigned char retval = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; MAX31865_CS = 0;<br> &nbsp; &nbsp; SPI_Write(address &amp; 0x7F);<br> &nbsp; &nbsp; retval = SPI_Read(0x00);<br> &nbsp; &nbsp; MAX31865_CS = 1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return retval;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The timing diagram for the SPI bus read matches the code given above.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-93.png\" alt=\"\" class=\"wp-image-15275\" width=\"470\" height=\"120\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-93.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-93-580x147.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-93-768x195.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The rest of the code is all about collecting and processing RTD data as per the datasheet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Just like byte read and write, there are functions for word-sized read and write. These functions utilize the byte read and write functions.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned int MAX31865_read_word(unsigned char address)<br> {<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned int retval = 0x0000;<br> &nbsp;<br> &nbsp; &nbsp; hb = MAX31865_read_byte(address);<br> &nbsp; &nbsp; lb = MAX31865_read_byte(address + 1);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; retval = hb;<br> &nbsp; &nbsp; retval &lt;&lt;= 0x08;<br> &nbsp; &nbsp; retval |= lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return retval;<br> }<br> &nbsp;<br> ....<br> void MAX31865_write_word(unsigned char address, unsigned char lb, unsigned char hb)<br> {<br> &nbsp; &nbsp; MAX31865_write_byte(address, hb);<br> &nbsp; &nbsp; MAX31865_write_byte((address + 1), lb);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Going further, there is a function to read raw data from the RTD sensor. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned int MAX31865_get_RTD(void)<br> {<br> &nbsp; unsigned int rtd_value = 0x00;<br> &nbsp; <br> &nbsp; rtd_value = MAX31865_read_word(MAX31865_RTD_MSB_REG);<br> &nbsp; rtd_value &gt;&gt;= 1;<br> &nbsp; <br> &nbsp; return rtd_value;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As per the datasheet, the raw RTD data is 15-bits wide and so a word read operation is needed. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-94.png\" alt=\"\" class=\"wp-image-15276\" width=\"470\" height=\"119\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-94.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-94-580x146.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-94-768x194.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">With the raw RTD data extracted, we can calculate RTD resistance and temperature after further data processing. This is done in the following function: <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> signed int MAX31865_get_temperature(void)<br> {<br> &nbsp; &nbsp; float rt = 0.0;<br> &nbsp; &nbsp; signed int t_value = 0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; t_value = MAX31865_get_RTD();<br> &nbsp; &nbsp; rt = (MAX31865_Reference_Resistance * t_value);<br> &nbsp; &nbsp; rt \/= 32768.0;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; rt \/= MAX31865_RTD_Nominal_Value;<br> &nbsp; &nbsp; rt = (rt - 1.0);<br> &nbsp; &nbsp; t_value = (rt \/ MAX31865_RTD_A);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return t_value;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the main, the temperature read by the chip is displayed on the on board seven-segment display. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; MAX31865_init();<br> &nbsp;<br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = MAX31865_get_temperature();<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(600);<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"527\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-95.png\" alt=\"\" class=\"wp-image-15277\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-95.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-95-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-95-768x431.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - SPI Communication - MAX31865 PT100 (3 Wire) RTD Amplifier\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/xW0eEuduWUE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - SPI Communication - MAX31865 PT100 (2 Wire) RTD Amplifier\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/B1PCc6lLt8c?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">I2C\/SMBUS \u2013 HMC5883L Digital Compass<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Going through the datasheet of C805F330D, we will not find any I2C hardware present in it. The same applies to the MikroC compiler. However, there is an SMBus hardware present. SMBus and I2C are compatible with each other, the only differences being the maximum bus speed and the timeout feature. Both I2C and SMBus are two-wire interfaces. Thus, whenever we need to hook up I2C devices with our C8051 microcontrollers, we can use SMBus without any issues.&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-96.png\" alt=\"\" class=\"wp-image-15279\" width=\"705\" height=\"239\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-96.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-96-580x197.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-96-768x261.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">There\nare tons of articles dedicated to I2C and SMBus protocols and so to know more\nabout them the following links are very informative:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/learn.mikroe.com\/i2c-everything-need-know\">https:\/\/learn.mikroe.com\/i2c-everything-need-know<\/a>&nbsp;\n<\/li><li><a href=\"https:\/\/learn.sparkfun.com\/tutorials\/i2c\">https:\/\/learn.sparkfun.com\/tutorials\/i2c<\/a>&nbsp;\n<\/li><li><a href=\"http:\/\/www.ti.com\/lsds\/ti\/interface\/i2c-overview.page\">http:\/\/www.ti.com\/lsds\/ti\/interface\/i2c-overview.page<\/a>&nbsp;&nbsp;\n<\/li><li><a href=\"http:\/\/www.robot-electronics.co.uk\/i2c-tutorial\">http:\/\/www.robot-electronics.co.uk\/i2c-tutorial<\/a>&nbsp;\n<\/li><li><a href=\"https:\/\/www.i2c-bus.org\/i2c-bus\">https:\/\/www.i2c-bus.org\/i2c-bus<\/a>&nbsp;\n<\/li><li><a href=\"http:\/\/i2c.info\">http:\/\/i2c.info<\/a>&nbsp;\n<\/li><li><a href=\"https:\/\/www.totalphase.com\/support\/articles\/200349186-Differences-between-I2C-and-SMBus\">https:\/\/www.totalphase.com\/support\/articles\/200349186-Differences-between-I2C-and-SMBus<\/a> <\/li><li><a href=\"https:\/\/www.nxp.com\/docs\/en\/application-note\/AN4471.pdf\">https:\/\/www.nxp.com\/docs\/en\/application-note\/AN4471.pdf<\/a> <\/li><li><a href=\"https:\/\/www.i2c-bus.org\/smbus\/\">https:\/\/www.i2c-bus.org\/smbus\/<\/a> <\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">HMC5883L.h<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define HMC5883L_READ_ADDR &nbsp; &nbsp; &nbsp; 0x3D<br> #define HMC5883L_WRITE_ADDR &nbsp; &nbsp; &nbsp;0x3C<br> &nbsp;<br> #define Config_Reg_A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x00<br> #define Config_Reg_B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x01<br> #define Mode_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x02<br> #define X_MSB_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x03<br> #define X_LSB_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x04<br> #define Z_MSB_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x05<br> #define Z_LSB_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x06<br> #define Y_MSB_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x07<br> #define Y_LSB_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x08<br> #define Status_Reg &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x09<br> #define ID_Reg_A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0A &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> #define ID_Reg_B &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0B <br> #define ID_Reg_C &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x0C<br> &nbsp;<br> #define PI &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3.142<br> #define declination_angle &nbsp; &nbsp; -0.5167 &nbsp; &nbsp; &nbsp; &nbsp;\/\/ For Uttara, Dhaka, Bangladesh<br> &nbsp;<br> signed int X_axis = 0;<br> signed int Y_axis = 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> signed int Z_axis = 0;<br> float m_scale = 1.0;<br> &nbsp;<br> unsigned int make_word(unsigned char HB, unsigned char LB);<br> void HMC5883L_init(void);<br> unsigned char HMC5883L_read(unsigned char reg);<br> void HMC5883L_write(unsigned char reg_address, unsigned char value);<br> void HMC5883L_read_data(void);<br> void HMC5883L_scale_axes(void);<br> void HMC5883L_set_scale(float gauss); <br> float HMC5883L_heading(void); <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">HMC5883L.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"HMC5883L.h\"<br> &nbsp;<br> unsigned int make_word(unsigned char HB, unsigned char LB)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned int val = 0; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; val = HB; <br> &nbsp; &nbsp; val &lt;&lt;= 8; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; val |= LB;<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; return val; <br> } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> void HMC5883L_init(void)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; SMBus1_Init(20000);<br> &nbsp; &nbsp; HMC5883L_write(Config_Reg_A, 0x70);<br> &nbsp; &nbsp; HMC5883L_write(Config_Reg_B, 0xA0); <br> &nbsp; &nbsp; HMC5883L_write(Mode_Reg, 0x00); &nbsp;<br> &nbsp; &nbsp; HMC5883L_set_scale(1.3); <br> }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp;<br> unsigned char HMC5883L_read(unsigned char reg)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned char val = 0; <br> &nbsp; &nbsp; <br> &nbsp; &nbsp; SMBus1_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_WRITE_ADDR);<br> &nbsp; &nbsp; SMBus1_Write(reg);<br> &nbsp; &nbsp; SMBus1_Repeated_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_READ_ADDR);<br> &nbsp; &nbsp; val = SMBus1_Read(0);<br> &nbsp; &nbsp; SMBus1_Stop();<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; return(val); &nbsp; <br> }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> void HMC5883L_write(unsigned char reg_address, unsigned char value)<br> {<br> &nbsp; &nbsp; SMBus1_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_WRITE_ADDR);<br> &nbsp; &nbsp; SMBus1_Write(reg_address);<br> &nbsp; &nbsp; SMBus1_Write(value);<br> &nbsp; &nbsp; SMBus1_Stop();<br> } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp;<br> &nbsp;<br> void HMC5883L_read_data(void)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned char lsb = 0; <br> &nbsp; &nbsp; unsigned char msb = 0; <br> &nbsp; &nbsp; <br> &nbsp; &nbsp; SMBus1_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_WRITE_ADDR);<br> &nbsp; &nbsp; SMBus1_Write(X_MSB_Reg);<br> &nbsp; &nbsp; SMBus1_Repeated_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_READ_ADDR);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; msb = SMBus1_Read(1);<br> &nbsp; &nbsp; lsb = SMBus1_Read(1);<br> &nbsp; &nbsp; X_axis = make_word(msb, lsb); <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; msb = SMBus1_Read(1);<br> &nbsp; &nbsp; lsb = SMBus1_Read(1);<br> &nbsp; &nbsp; Z_axis = make_word(msb, lsb);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; msb = SMBus1_Read(1);<br> &nbsp; &nbsp; lsb = SMBus1_Read(0);<br> &nbsp; &nbsp; Y_axis = make_word(msb, lsb); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; SMBus1_Stop();<br> } <br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> void HMC5883L_scale_axes(void)<br> { &nbsp; &nbsp;<br> &nbsp; &nbsp; X_axis *= m_scale;<br> &nbsp; &nbsp; Z_axis *= m_scale; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; Y_Axis *= m_scale; <br> }<br> &nbsp;<br> void HMC5883L_set_scale(float gauss) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> {<br> &nbsp; &nbsp; unsigned char value = 0;<br> &nbsp;<br> &nbsp; &nbsp; if(gauss == 0.88)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 0.73;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 1.3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x01;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 0.92;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 1.9)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x02;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 1.22;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 2.5)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x03;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 1.52;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 4.0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x04;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 2.27;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 4.7)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x05;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 2.56;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 5.6)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x06;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 3.03;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; else if(gauss == 8.1)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0x07;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_scale = 4.35;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; value &lt;&lt;= 5;<br> &nbsp; &nbsp; &nbsp; &nbsp; HMC5883L_write(Config_Reg_B, value);<br> } &nbsp; &nbsp; <br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> float HMC5883L_heading(void)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; float heading = 0.0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; HMC5883L_read_data();<br> &nbsp; &nbsp; HMC5883L_scale_axes();<br> &nbsp; &nbsp; heading = atan2(Y_axis, X_axis);<br> &nbsp; &nbsp; heading += declination_angle; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; if(heading &lt; 0.0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; heading += (2.0 * PI);<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(heading &gt; (2.0 * PI)) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; heading -= (2.0 * PI);<br> &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; heading *= (180.0 \/ PI); <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; return heading;<br> } &nbsp; <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"HMC5883L.c\"<br> &nbsp;<br> #define LED_DOUT P1_6_bit<br> #define &nbsp;LED_CLK P1_5_bit<br> #define &nbsp;LED_LATCH P1_7_bit<br> &nbsp;<br> unsigned char i = 0;<br> signed int h = 0;<br> unsigned char val = 0;<br> &nbsp;<br> const unsigned char code segment_code[13] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF, \/\/ -<br> &nbsp; 0x9C &nbsp;\/\/ deg<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void SMBus_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_ISR()<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (h \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((h % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (h % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 12;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; &nbsp;Init_Device();<br> &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp;while(1)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;h = HMC5883L_heading();<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(200);<br> &nbsp; &nbsp; &nbsp;}<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void SMBus_Init(void)<br> {<br> &nbsp; &nbsp; SMB0CF = 0x80;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;SDA (SMBus), Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;SCL (SMBus), Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x04;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; SMBus_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> &nbsp; &nbsp; HMC5883L_init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"474\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-97.png\" alt=\"\" class=\"wp-image-15280\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-97.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-97-580x292.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-97-768x387.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">HMC5883L is a popular digital geomagnetic sensor or simply compass sensor that uses the I2C bus interface for communication. Since I2C and SMBUS are similar in terms of working principle, we can use the SMBUS interface to hook up this sensor with C8051F330. Shown below is the basic interfacing diagram:&nbsp;&nbsp;&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-98.png\" alt=\"\" class=\"wp-image-15281\" width=\"345\" height=\"150\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-98.png 689w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-98-580x253.png 580w\" sizes=\"auto, (max-width: 345px) 100vw, 345px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To be able to successfully use SMBUS\/I2C\ninterface, we have to code according to the instructions given in the device\ndatasheet. We have to be specifically attentive to I2C bus read and write\noperations because these are the operations that are used for data\ntransactions. Generally, these operations do not vary from device to device.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I2C\/SMBUS read process can be simply defined by the following functions and flow diagram. In our case with the HMC5883L digital compass, we have to begin communication by initiating a \u201cStart\u201d condition in the bus. This is followed by providing the 7-bit I2C slave address of the compass along with the write bit. If things are sent without any issue, the slave would issue an acknowledgement. It is not mandatory to check acknowledgement at this time. Acknowledgement is only needed to be checked when data is read but we have to specify which register is required to be read. Before actually reading the register, we want to read the I2C bus is restarted along with the 7-bit I2C slave address of the compass with the read bit attached to it.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-99.png\" alt=\"\" class=\"wp-image-15282\" width=\"940\" height=\"111\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-99.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-99-580x68.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-99-768x91.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned char HMC5883L_read(unsigned char reg)<br> { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; unsigned char val = 0; <br> &nbsp; &nbsp; <br> &nbsp; &nbsp; SMBus1_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_WRITE_ADDR);<br> &nbsp; &nbsp; SMBus1_Write(reg);<br> &nbsp; &nbsp; SMBus1_Repeated_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_READ_ADDR);<br> &nbsp; &nbsp; val = SMBus1_Read(0);<br> &nbsp; &nbsp; SMBus1_Stop();&nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; return(val); &nbsp; <br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The writing process is yet simpler all we have to do is to specify the register we wish to write followed by the value we want to write. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-100.png\" alt=\"\" class=\"wp-image-15283\" width=\"706\" height=\"119\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-100.png 706w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-100-580x98.png 580w\" sizes=\"auto, (max-width: 706px) 100vw, 706px\" \/><\/figure><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\"> void HMC5883L_write(unsigned char reg_address, unsigned char value)<br> {<br> &nbsp; &nbsp; SMBus1_Start();<br> &nbsp; &nbsp; SMBus1_Write(HMC5883L_WRITE_ADDR);<br> &nbsp; &nbsp; SMBus1_Write(reg_address);<br> &nbsp; &nbsp; SMBus1_Write(value);<br> &nbsp; &nbsp; SMBus1_Stop();<br> } &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Once we establish these two read-and-write processes, we are left with coding the compass as per the datasheet. This enables us to use the compass for real-world applications.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-101.png\" alt=\"\" class=\"wp-image-15284\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-101.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-101-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-101-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - SMBUS - HMC5883L I2C Digital Compass\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/50upZAW4W_A?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">One Wire Bus (OW) \u2013 DS18B20 Digital\nTemperature Sensor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MikroC compiler packs a lot of common regular-use libraries apart from SPI, UART and I2C libraries. One wire library is one such library that is not usually seen in other compilers. This library allows us to communicate with one-wire devices from Dallas like DS18B20 digital temperature sensors and other one-wire devices from the same manufacturer.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-102.png\" alt=\"\" class=\"wp-image-15286\" width=\"388\" height=\"261\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-102.png 775w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-102-580x391.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-102-768x517.png 768w\" sizes=\"auto, (max-width: 388px) 100vw, 388px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_7_bit<br> &nbsp;<br> #define DS18B20_CONVERT_T &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x44<br> #define DS18B20_READ_SCRATCHPAD &nbsp; &nbsp; &nbsp; &nbsp; 0xBE<br> #define DS18B20_SKIP_ROM &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0xCC<br> &nbsp;<br> sbit OW_Bit at P1_4_bit;<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x9C, \/\/ degree<br> &nbsp; 0xC6 &nbsp;\/\/ C<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void Reset_Sources_Init(void);<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 11;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned temp = 0x00;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Reset();<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_SKIP_ROM);<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_CONVERT_T);<br> &nbsp; &nbsp; &nbsp; &nbsp; Delay_us(120);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Reset();<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_SKIP_ROM);<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_READ_SCRATCHPAD);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; temp = &nbsp;Ow_Read();<br> &nbsp; &nbsp; &nbsp; &nbsp; temp = ((Ow_Read() &lt;&lt; 0x08) + temp);<br> &nbsp; &nbsp; &nbsp; &nbsp; value = temp &gt;&gt; 0x04;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(300);<br> &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(300);<br> &nbsp;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void Reset_Sources_Init(void)<br> {<br> &nbsp; &nbsp; RSTSRC = 0x04;<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0xCA;<br> &nbsp; &nbsp; TMR3RLH = 0xFA;<br> }<br> &nbsp;<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Analog<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDIN = 0xF3;<br> &nbsp; &nbsp; P0MDOUT = 0x02;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x0E;<br> &nbsp; &nbsp; P1SKIP = 0xD0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; int i = 0;<br> &nbsp; &nbsp; OSCICN = 0x81;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(MCDRSF_bit == 1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; CLKSEL = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 9; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; OSCXCN = 0x67;<br> &nbsp; &nbsp; &nbsp; &nbsp; for (i = 0; i &lt; 3000; i++); &nbsp;\/\/ Wait 1ms for initialization<br> &nbsp; &nbsp; &nbsp; &nbsp; while ((OSCXCN &amp; 0x80) == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; CLKSEL = 0x01;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 9; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; delay_ms(2000);<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Reset_Sources_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-103.png\" alt=\"\" class=\"wp-image-15287\" width=\"705\" height=\"350\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-103.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-103-580x288.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-103-768x381.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">DS18B20 digital temperature sensor employs a time-slotting mechanism for data transactions, the basics of which are shown below.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-104.png\" alt=\"\" class=\"wp-image-15288\" width=\"470\" height=\"340\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-104.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-104-580x420.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-104-768x556.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">MikroC compiler has a dedicated one-wire\nlibrary for this sensor and many other devices that employ one-wire protocol as\nper specification from Dallas. In this example, I used their library to\ncommunicate with a DS18B20 temperature sensor and the entire process is very\nsimple. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The main code begins by issuing one-wire\nreset command (<em>Ow_Reset<\/em>) followed by ROM skipping and temperature\nconvert commands. The reset command acts like a flush. The ROM skip command is\nused because there is only one DS18B20 present in the one-wire bus in this\nexample. If there were multiple sensors present in the same bus then we could\nidentify them by reading their unique identification code stored inside their\nROMs. The \u201c<em>temperature convert\u201d<\/em> command, on the other hand, reads the\ninternal ADC of the sensor and converts the analogue temperature value to\ndigital binary data. After this, we have to wait for a small duration of 120\nmicroseconds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The above process is repeated but the temperature conversion command is replaced with the scratchpad read command because the converted temperature binary data is stored in an internal scratchpad or RAM location. The sensor is read and necessary conversions are done to extract temperature in human-readable decimal format. The temperature is then displayed on the onboard seven-segment display.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned temp = 0x00;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Reset();<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_SKIP_ROM);<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_CONVERT_T);<br> &nbsp; &nbsp; &nbsp; &nbsp; Delay_us(120);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Reset();<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_SKIP_ROM);<br> &nbsp; &nbsp; &nbsp; &nbsp; Ow_Write(DS18B20_READ_SCRATCHPAD);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; temp = &nbsp;Ow_Read();<br> &nbsp; &nbsp; &nbsp; &nbsp; temp = ((Ow_Read() &lt;&lt; 0x08) + temp);<br> &nbsp; &nbsp; &nbsp; &nbsp; value = temp &gt;&gt; 0x04;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(300);<br> &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(300);<br> &nbsp;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There is one thing in the code that needs to be discussed here. In this example code, I used a trick to ensure that the program works even if the 12MHz external oscillator attached to the microcontroller fails for some reason. For this, I enabled the missing clock detector reset. It works simply by resetting the microcontroller in the event of a missing clock signal from an external oscillator. After a reset or during start-up, the code checks whether there is a history of reset due to external oscillator failure or not. This is done by checking the <strong><em>MCDESF<\/em><\/strong> flag bit. If there was a reset due to external oscillator failure then the code switches to the internal oscillator automatically or else the external oscillator is selected. The oscillator selection is shown by flashing a LED connected with P0.1 pin. The flashing rate indicates which clock source has been selected. A fast flash rate indicates external oscillator selection while a slow flash rate indicates internal oscillator selection.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Reset_Sources_Init(void)<br> {<br> &nbsp; &nbsp; RSTSRC = 0x04;<br> }<br> &nbsp;<br> ....<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; int i = 0;<br> &nbsp; &nbsp; OSCICN = 0x81;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(MCDRSF_bit == 1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; CLKSEL = 0x00;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 9; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; OSCXCN = 0x67;<br> &nbsp; &nbsp; &nbsp; &nbsp; for (i = 0; i &lt; 3000; i++); &nbsp;\/\/ Wait 1ms for initialization<br> &nbsp; &nbsp; &nbsp; &nbsp; while ((OSCXCN &amp; 0x80) == 0);<br> &nbsp; &nbsp; &nbsp; &nbsp; CLKSEL = 0x01;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 9; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; delay_ms(2000);<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-105.png\" alt=\"\" class=\"wp-image-15289\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-105.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-105-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-105-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - One Wire Communication (DS18B20) and System Clock Failure Simulation\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/qE_B88fMvfY?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Bit-Banging \u2013 RF Communication with\nRF Modules<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In many situations, we need to create our communication protocol and in those cases bit-banging I\/O pins are the only method we have to resort to. On the other hand, there is no other better way other than bit-banging to reliably transmit-receive data between low-cost 315\/433 MHz RF modules. Using UART is an alternative but some microcontrollers lack these hardware peripherals while in other cases, it may have other uses. Another important thing to note is the fact that RF modules of these frequency ranges pickup lot of background RF noise and so there is no simple technique to reliably transmit and receive valid data. Thus, we need some sort of data encapsulation.&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-106.png\" alt=\"\" class=\"wp-image-15291\" width=\"446\" height=\"431\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-106.png 891w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-106-580x561.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-106-768x743.png 768w\" sizes=\"auto, (max-width: 446px) 100vw, 446px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">RF TX main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_7_bit<br> &nbsp;<br> #define INC_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_4_bit<br> #define DEC_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_3_bit<br> &nbsp;<br> #define RF_RX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P0_0_bit<br> #define RF_TX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P0_1_bit<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> void send_data(unsigned char value);<br> void RF_send(unsigned char rf_data);<br> &nbsp;<br> unsigned char i = 0;<br> unsigned char val = 0;<br> signed int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void Timer_3_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value--;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(value &gt; 200)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 99;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; send_data(value);<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(100);<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x02;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x03;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; LED_LATCH = 1;<br> }<br> &nbsp;<br> void send_data(unsigned char value)<br> {<br> &nbsp; &nbsp; &nbsp;signed char s = 20;<br> &nbsp; &nbsp; &nbsp;unsigned char CRC = 0;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;CRC = (value &amp; 0xAA);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;while(s &gt; 0x00)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_us(500);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_us(500);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;delay_us(100);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;RF_send(value);<br> &nbsp; &nbsp; &nbsp;RF_send(CRC);<br> }<br> &nbsp;<br> void RF_send(unsigned char rf_data)<br> {<br> &nbsp; &nbsp; signed char s = 0x08;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(s &gt; 0x00)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(rf_data &amp; 0x80)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(2);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rf_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">RF RX main.c <\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_7_bit<br> &nbsp;<br> #define RF_RX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P0_0_bit<br> #define RF_TX &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P0_1_bit<br> &nbsp;<br> #define sync &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x09<br> #define error &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x06<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> unsigned char receive_data(void);<br> signed long decode_data(void);<br> &nbsp;<br> unsigned char i = 0;<br> unsigned char val = 0;<br> signed int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void Timer_3_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp;<br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = decode_data();<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x02;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x03;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; LED_LATCH = 1;<br> }<br> &nbsp;<br> unsigned char receive_data(void)<br> {<br> &nbsp; &nbsp; unsigned char t = 0;<br> &nbsp;<br> &nbsp; &nbsp; while(!RF_RX);<br> &nbsp; &nbsp; while(RF_RX)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; t++;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(10);<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; if((t &gt; 25) &amp;&amp; (t &lt; 75))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return sync;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((t &gt; 175) &amp;&amp; (t &lt; 225))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return 1;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((t &gt; 75) &amp;&amp; (t &lt; 125))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return error;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> signed long decode_data(void)<br> {<br> &nbsp; &nbsp; unsigned char d = 0;<br> &nbsp; &nbsp; unsigned char s = 0;<br> &nbsp; &nbsp; unsigned long value = 0;<br> &nbsp; &nbsp; unsigned char v1 = 0;<br> &nbsp; &nbsp; unsigned char v2 = 0;<br> &nbsp;<br> &nbsp; &nbsp; while(receive_data() != sync);<br> &nbsp;<br> &nbsp; &nbsp; d = receive_data();<br> &nbsp; &nbsp; while(d == sync)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d = receive_data();<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; while(s &lt; 15)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; switch(d)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value |= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case sync:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case error:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return -1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; s++;<br> &nbsp; &nbsp; &nbsp; &nbsp; value &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; d = receive_data();<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; v1 = (value &gt;&gt; 8);<br> &nbsp; &nbsp; v2 = (value &amp; 0x00FF);<br> &nbsp; &nbsp; delay_ms(4);<br> &nbsp;<br> &nbsp; &nbsp; if((v1 &amp; 0xAA) == v2)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return v1;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return -1;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Schematic<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">RF TX<\/h4>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-107.png\" alt=\"\" class=\"wp-image-15292\" width=\"705\" height=\"352\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-107.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-107-580x289.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-107-768x383.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">RF RX<\/h4>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-108.png\" alt=\"\" class=\"wp-image-15293\" width=\"705\" height=\"355\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-108.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-108-580x292.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-108-768x386.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">RF modules usually come in pairs &#8211; a transmitter and a receiver. &nbsp;<em>P0.0<\/em> and <em>P0.1<\/em> are <em>RF TX<\/em> and <em>RF RX<\/em> pins respectively. These pins are bit-banged. Two C8051F330D microcontroller boards have been used in this example \u2013 one is a transmitter and the other is a receiver. The modules used in this example are similar to the ones shown below although any other RF module of similar nature would work fine. I have tested this example with various other RF modules including 315 MHz ones without any issues. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-109.png\" alt=\"\" class=\"wp-image-15294\" width=\"470\" height=\"190\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-109.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-109-580x235.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-109-768x311.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The bit-banging technique employed here is based on the time-slotting technique similar to DS18B20 digital temperature sensor. Ones and zeroes are defined by pulse widths. There is no additional hardware peripheral needed apart from I\/O pins to achieve bit-banging.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-110.png\" alt=\"\" class=\"wp-image-15295\" width=\"470\" height=\"122\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-110.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-110-580x150.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-110-768x199.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As shown in the illustration above, a <em>\u201cOne\u201d <\/em>is a pulse of 2 ms high followed by a 1 ms low while a <em>\u201cZero\u201d <\/em>is a pulse of 1 ms high followed by a 1 ms low pin state. The following function will take RF data byte to be sent via RF module and will convert it to time-slotting pulses. Data is sent from MSB to LSB. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void RF_send(unsigned char rf_data)<br> {<br> &nbsp; &nbsp; signed char s = 0x08;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(s &gt; 0x00)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(rf_data &amp; 0x80)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(2);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(1);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rf_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The above function is just for time-slotting-based bit-banging. However, data that is to be sent needs to be encapsulated in a proper manner so that whatever we send is reliably received by the receiver without any issue. Therefore, we need a mechanism to add a cyclic redundancy check (CRC) along with the data. The following function will accept a byte of data and send it to an RF receiver via an RF medium. There are two steps in between. Generally, an RF receiver module tends to receive a lot of background RF noise due to its default high RF gain setting. Due to this effect, it continuously outputs random pulses even when nothing valid is being transmitted by any transmitter. Thus, a technique is needed to reduce the RF receiver\u2019s gain so that it can pick up the correct transmitted data. This can be achieved by sending a stream of high-frequency pulses. Once the RF gain is reduced, we can reliably send data. However, there could be errors during the reception of data and so a CRC check becomes mandatory. This CRC check would ensure whether the data received is correct or false. The <em>send_data<\/em> function given below does all of these steps. For simplicity, the CRC here is simply the result of an <em>AND<\/em> operation between data to be sent and 0xAA. &nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void send_data(unsigned char value)<br> {<br> &nbsp; &nbsp; &nbsp;signed char s = 20;<br> &nbsp; &nbsp; &nbsp;unsigned char CRC = 0;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;CRC = (value &amp; 0xAA);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;while(s &gt; 0x00)<br> &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_us(500);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;RF_TX = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_us(500);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp;delay_us(100);<br> &nbsp;<br> &nbsp; &nbsp; &nbsp;RF_send(value);<br> &nbsp; &nbsp; &nbsp;RF_send(CRC);<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now let us look at the receiver side. The receiver side has just to decode and reconstruct what has been sent to it. Since the time-slotting technique has been used to send data, we just have to check pulse widths to determine if received pulses are sync, one or zero pulses. For logic low at the RF RX pin, we have to do nothing. It is only during a logic high that we time the high period. The timing is done in 10\u00b5s steps in order to ensure pulse timing accuracy while ensuring that all kinds of pulses are properly polled. A time-keeping variable, <em>t<\/em> is responsible for keeping time. It gets incremented every 10\u00b5s when the RF RX pin is held in the high state. When the RF Rx pin gets low afterward, pulse width time is obtained. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Due to the effects of environment, temperature, medium, oscillator mismatch and other factors, pulse timings may deviate and so all timings are compared in ranges instead of fixed values of 0.5ms, 1ms and 2ms, i.e., there are tolerances in timings. Any pulse that does not fit in these ranges is discarded as a glitch. The <em>receive_data<\/em> function given below does all of the aforementioned tasks.&nbsp; &nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> unsigned char receive_data(void)<br> {<br> &nbsp; &nbsp; unsigned char t = 0;<br> &nbsp;<br> &nbsp; &nbsp; while(!RF_RX);<br> &nbsp; &nbsp; while(RF_RX)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; t++;<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_us(10);<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; if((t &gt; 25) &amp;&amp; (t &lt; 75))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return sync;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((t &gt; 175) &amp;&amp; (t &lt; 225))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return 1;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else if((t &gt; 75) &amp;&amp; (t &lt; 125))<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return error;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now that we understand how the pulses are obtained, we can now focus on how the received pulses are decoded to obtain sent data. Until sync pulses have been successfully obtained, no other received data is processed. If sync pulses have been detected properly then the next 16 bits are polled and the sent data and CRC are reconstructed. At the end of these steps, CRC is calculated and cross-checked against the sent CRC value.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define sync &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0x09<br> #define error &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0x06<br> &nbsp;<br> ....<br> &nbsp;<br> signed long decode_data(void)<br> {<br> &nbsp; &nbsp; unsigned char d = 0;<br> &nbsp; &nbsp; unsigned char s = 0;<br> &nbsp; &nbsp; unsigned long value = 0;<br> &nbsp; &nbsp; unsigned char v1 = 0;<br> &nbsp; &nbsp; unsigned char v2 = 0;<br> &nbsp;<br> &nbsp; &nbsp; while(receive_data() != sync);<br> &nbsp;<br> &nbsp; &nbsp; d = receive_data();<br> &nbsp; &nbsp; while(d == sync)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;d = receive_data();<br> &nbsp; &nbsp; };<br> &nbsp;<br> &nbsp; &nbsp; while(s &lt; 15)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; switch(d)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value |= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case sync:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case error:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return -1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; s++;<br> &nbsp; &nbsp; &nbsp; &nbsp; value &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; d = receive_data();<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; v1 = (value &gt;&gt; 8);<br> &nbsp; &nbsp; v2 = (value &amp; 0x00FF);<br> &nbsp; &nbsp; delay_ms(4);<br> &nbsp;<br> &nbsp; &nbsp; if((v1 &amp; 0xAA) == v2)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return v1;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; return -1;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the main code of the transmitter, the value of a variable named <em>value<\/em> is changed using two onboard push buttons connected to P1.4 and P1.4 and sent every 100ms via RF medium using an RF transmitter module. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(40);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value--;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(value &gt; 200)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(value &lt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value = 99;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; send_data(value);<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(100);<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At the receiver side, the value sent by the transmitter is decoded and shown on the onboard seven-segment display.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp;<br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; value = decode_data();<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"528\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-111.png\" alt=\"\" class=\"wp-image-15296\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-111.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-111-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-111-768x431.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - RF Communication with Short-Range RF Modules\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/Hu_T04OuNSM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Bit-banging - IrDA Communication using Infrared Transmitter and Receiver\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/omz91oPcOnA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Watchdog Timer (WDT)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As anyone would expect in a microcontroller,\nC8051s pack watchdog timers for resetting them in the event of unexpected or\nunforeseen loop or software failure, leading to unwanted code execution halt. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unlike most microcontrollers, however, there\nis no separate and dedicated watchdog timer in C8051F330D. The watchdog timer\nof C8051F330D is part of the Programmable Array Counter (PCA) hardware\u2019s module\n2 and so there are some advantages and disadvantages to this arrangement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In terms of advantages, firstly no additional\nexternal hardware is needed and secondly, the implementation is not complex.\nThe disadvantages are, dependency on the system clock for timing rather than a\nseparate independent watchdog timer clock, loss of one PCA module if watchdog\ntimer mode is used and difficulty in locating it in the datasheet. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">According to the block diagram shown below, the PCA watchdog timer works by using the compare-match principle. If a match occurs between PCA0CPH2 and PCA0H while the WDT is enabled, a reset will be generated. By default, the watchdog timer is enabled.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-112.png\" alt=\"\" class=\"wp-image-15298\" width=\"367\" height=\"188\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-112.png 734w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-112-580x296.png 580w\" sizes=\"auto, (max-width: 367px) 100vw, 367px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; P1_7_bit<br> #define BUTTON &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_4_bit<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_ISR()<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((value % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; signed int s = 200;<br> &nbsp; <br> &nbsp; Init_Device();<br> &nbsp;<br> &nbsp; while(1)<br> &nbsp; {<br> &nbsp; &nbsp; &nbsp; value++;<br> &nbsp; &nbsp; &nbsp; delay_ms(20);<br> &nbsp; &nbsp; &nbsp; if(BUTTON == 1)<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while(s &gt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while(1);<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init()<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> &nbsp; &nbsp; PCA0CPM2 = 0x01;<br> &nbsp; &nbsp; PCA0CPL2 = 0xFF;<br> &nbsp; &nbsp; PCA0MD |= 0x40;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xF0;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LED_LATCH = 1;<br> &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-113.png\" alt=\"\" class=\"wp-image-15299\" width=\"705\" height=\"353\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-113.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-113-580x290.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-113-768x384.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The following formula and table show some typical watchdog timeout values.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-114.png\" alt=\"\" class=\"wp-image-15300\" width=\"283\" height=\"246\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-115.png\" alt=\"\" class=\"wp-image-15301\" width=\"602\" height=\"159\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-115.png 602w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-115-580x153.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-115-600x159.png 600w\" sizes=\"auto, (max-width: 602px) 100vw, 602px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Thus with 24.5MHz internal oscillator, <em>PCA0CPL2<\/em> = 255 and <em>PCA0L <\/em>= 0, the timeout is calculated as below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-116.png\" alt=\"\" class=\"wp-image-15302\" width=\"603\" height=\"165\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-116.png 603w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-116-580x159.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-116-600x165.png 600w\" sizes=\"auto, (max-width: 603px) 100vw, 603px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The <strong><em>Config2<\/em><\/strong> code configuration\nwizard can be used to generate necessary code automatically and we can avoid\nall of these calculations but it is better to know how things are done\nmanually. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The setup for this example is just like all\nother examples covered so far. An onboard push button attached with pin P1.4\nand the onboard seven-segment display are both used. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The PCA watchdog setup for the calculation shown above is shown below.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA_Init()<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> &nbsp; &nbsp; PCA0CPM2 = 0x01;<br> &nbsp; &nbsp; PCA0CPL2 = 0xFF;<br> &nbsp; &nbsp; PCA0MD |= 0x40;<br> &nbsp; &nbsp; PCA0CPH2 = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After start-up, the code begins incrementing a variable named <em>value<\/em> and its value is shown on the onboard seven-segment display.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; signed int s = 200;<br> &nbsp; <br> &nbsp; Init_Device();<br> &nbsp;<br> &nbsp; while(1)<br> &nbsp; {<br> &nbsp; &nbsp; &nbsp; value++;<br> &nbsp; &nbsp; &nbsp; delay_ms(20);<br> &nbsp; &nbsp; &nbsp; if(BUTTON == 1)<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(20);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while(s &gt; 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PCA0CPH2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delay_ms(30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s--;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while(1);<br> &nbsp; &nbsp; &nbsp; }<br> &nbsp; };<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unless the push button which is active-low by working principle is pressed, the variable keeps incrementing. Since the watchdog timer timeout is set to 32ms, the watchdog timer needs to be reset before this time expires and this is done by clearing the&nbsp;<em>PCA0CPH2<\/em>&nbsp;register every 20ms. If the button is pressed, the code first enters a&nbsp;<em>while<\/em>&nbsp;loop that still resets the watchdog timer every 30ms without incrementing the variable&nbsp;<em>value<\/em>. This simulates an unforeseen software bug or&nbsp;<em>stuck-like<\/em>&nbsp;or&nbsp;<em>hang-like<\/em>&nbsp;condition. The code then enters into a jobless indefinite&nbsp;<em>while<\/em>&nbsp;loop. Since the&nbsp;<em>PCA0CPH2<\/em>&nbsp;register is no longer cleared inside the jobless indefinite loop, it is gradually and internally increment until the timeout is reached. After the timeout period expires, the microcontroller is reset and the process repeats.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"529\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-117.png\" alt=\"\" class=\"wp-image-15303\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-117.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-117-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-117-768x432.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"533\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-118.png\" alt=\"\" class=\"wp-image-15304\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-118.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-118-580x329.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-118-768x436.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Watchdog Timer\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/Tewf0BUnf8g?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">PCA in PWM Mode \u2013 Clover RGB LED Lights<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">C8051s come with internal <strong><em>Programmable\nCounter Array (PCA)<\/em><\/strong> peripherals with different numbers of PCA I\/O\nchannels. PCA hardware can be used for waveform\/signal input capture,\nhigh-speed frequency outputs, software timer, etc apart from PWM outputs. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The very basic thing that we can do with the\ninternal PCA peripheral is Pulse-Width Modulation (PWM) generation. It needs no\nnew mentioning that PWM is used in numerous applications like switch-mode power\nsupplies, motor control, LED driving, etc. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">8 or 16-bit PWMs can be obtained from C8051s and they also offer many other advanced features that are typically needed in motor and power control applications. The following block diagrams show the PCA modules in 8- and 16-bit modes respectively. Both of these modes rely on the compare-match principle to achieve PWM generation. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-119.png\" alt=\"\" class=\"wp-image-15305\" width=\"413\" height=\"185\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-119.png 825w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-119-580x260.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-119-768x344.png 768w\" sizes=\"auto, (max-width: 413px) 100vw, 413px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-120.png\" alt=\"\" class=\"wp-image-15306\" width=\"410\" height=\"156\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-120.png 820w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-120-580x220.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-120-768x291.png 768w\" sizes=\"auto, (max-width: 410px) 100vw, 410px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> const code unsigned int LUT_1[32] = <br> {<br> &nbsp; &nbsp; &nbsp; 0, <br> &nbsp; &nbsp; &nbsp; 6423, <br> &nbsp; &nbsp; &nbsp; 12785, <br> &nbsp; &nbsp; &nbsp; 19023, <br> &nbsp; &nbsp; &nbsp; 25079, <br> &nbsp; &nbsp; &nbsp; 30892, <br> &nbsp; &nbsp; &nbsp; 36409, <br> &nbsp; &nbsp; &nbsp; 41574, <br> &nbsp; &nbsp; &nbsp; 46340, <br> &nbsp; &nbsp; &nbsp; 50659, <br> &nbsp; &nbsp; &nbsp; 54490, <br> &nbsp; &nbsp; &nbsp; 57796, <br> &nbsp; &nbsp; &nbsp; 60546, <br> &nbsp; &nbsp; &nbsp; 62713, <br> &nbsp; &nbsp; &nbsp; 64275, <br> &nbsp; &nbsp; &nbsp; 65219,<br> &nbsp; &nbsp; &nbsp; 65532,<br> &nbsp; &nbsp; &nbsp; 65219,<br> &nbsp; &nbsp; &nbsp; 64275, <br> &nbsp; &nbsp; &nbsp; 62713,<br> &nbsp; &nbsp; &nbsp; 60546,<br> &nbsp; &nbsp; &nbsp; 57796,<br> &nbsp; &nbsp; &nbsp; 54490,<br> &nbsp; &nbsp; &nbsp; 50659,<br> &nbsp; &nbsp; &nbsp; 46340,<br> &nbsp; &nbsp; &nbsp; 41574,<br> &nbsp; &nbsp; &nbsp; 36409,<br> &nbsp; &nbsp; &nbsp; 30892,<br> &nbsp; &nbsp; &nbsp; 25079,<br> &nbsp; &nbsp; &nbsp; 19023,<br> &nbsp; &nbsp; &nbsp; 12785,<br> &nbsp; &nbsp; &nbsp; 6423,<br> };<br> &nbsp;<br> const code unsigned int LUT_2[32] =<br> {<br> &nbsp; &nbsp; &nbsp; 54490,<br> &nbsp; &nbsp; &nbsp; 57796,<br> &nbsp; &nbsp; &nbsp; 60546,<br> &nbsp; &nbsp; &nbsp; 62713,<br> &nbsp; &nbsp; &nbsp; 64275,<br> &nbsp; &nbsp; &nbsp; 65219,<br> &nbsp; &nbsp; &nbsp; 65532,<br> &nbsp; &nbsp; &nbsp; 65219,<br> &nbsp; &nbsp; &nbsp; 64275,<br> &nbsp; &nbsp; &nbsp; 62713,<br> &nbsp; &nbsp; &nbsp; 60546,<br> &nbsp; &nbsp; &nbsp; 57796,<br> &nbsp; &nbsp; &nbsp; 54490,<br> &nbsp; &nbsp; &nbsp; 50659,<br> &nbsp; &nbsp; &nbsp; 46340,<br> &nbsp; &nbsp; &nbsp; 41574,<br> &nbsp; &nbsp; &nbsp; 36409,<br> &nbsp; &nbsp; &nbsp; 30892,<br> &nbsp; &nbsp; &nbsp; 25079,<br> &nbsp; &nbsp; &nbsp; 19023,<br> &nbsp; &nbsp; &nbsp; 12785,<br> &nbsp; &nbsp; &nbsp; 6423,<br> &nbsp; &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; &nbsp; 6423,<br> &nbsp; &nbsp; &nbsp; 12785,<br> &nbsp; &nbsp; &nbsp; 19023,<br> &nbsp; &nbsp; &nbsp; 25079,<br> &nbsp; &nbsp; &nbsp; 30892,<br> &nbsp; &nbsp; &nbsp; 36409,<br> &nbsp; &nbsp; &nbsp; 41574,<br> &nbsp; &nbsp; &nbsp; 46340,<br> &nbsp; &nbsp; &nbsp; 50659<br> };<br> &nbsp;<br> const code unsigned int LUT_3[32] =<br> {<br> &nbsp; &nbsp; &nbsp; 60546,<br> &nbsp; &nbsp; &nbsp; 57796,<br> &nbsp; &nbsp; &nbsp; 54490,<br> &nbsp; &nbsp; &nbsp; 50659,<br> &nbsp; &nbsp; &nbsp; 46340,<br> &nbsp; &nbsp; &nbsp; 41574,<br> &nbsp; &nbsp; &nbsp; 36409,<br> &nbsp; &nbsp; &nbsp; 30892,<br> &nbsp; &nbsp; &nbsp; 25079,<br> &nbsp; &nbsp; &nbsp; 19023,<br> &nbsp; &nbsp; &nbsp; 12785,<br> &nbsp; &nbsp; &nbsp; 6423,<br> &nbsp; &nbsp; &nbsp; 0,<br> &nbsp; &nbsp; &nbsp; 6423,<br> &nbsp; &nbsp; &nbsp; 12785,<br> &nbsp; &nbsp; &nbsp; 19023,<br> &nbsp; &nbsp; &nbsp; 25079,<br> &nbsp; &nbsp; &nbsp; 30892,<br> &nbsp; &nbsp; &nbsp; 36409,<br> &nbsp; &nbsp; &nbsp; 41574,<br> &nbsp; &nbsp; &nbsp; 46340,<br> &nbsp; &nbsp; &nbsp; 50659,<br> &nbsp; &nbsp; &nbsp; 54490,<br> &nbsp; &nbsp; &nbsp; 57796,<br> &nbsp; &nbsp; &nbsp; 60546,<br> &nbsp; &nbsp; &nbsp; 62713,<br> &nbsp; &nbsp; &nbsp; 64275,<br> &nbsp; &nbsp; &nbsp; 65219,<br> &nbsp; &nbsp; &nbsp; 65532,<br> &nbsp; &nbsp; &nbsp; 65219,<br> &nbsp; &nbsp; &nbsp; 64275,<br> &nbsp; &nbsp; &nbsp; 62713<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Init_Device(void);<br> void get_HB_LB(unsigned int value, unsigned char *HB, unsigned char *LB);<br> void PWM_0_duty_cycle(unsigned int value);<br> void PWM_1_duty_cycle(unsigned int value);<br> void PWM_2_duty_cycle(unsigned int value);<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned int i = 0;<br> &nbsp; &nbsp; unsigned char j = 0;<br> &nbsp; &nbsp; unsigned char mode = 1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 6; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 6; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 6; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 10; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(LUT_2[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(LUT_3[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(200);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; mode++;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(mode &gt; 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode &nbsp;= 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0CN = 0x40;<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x02;<br> &nbsp; &nbsp; PCA0CPM0 = 0xC2;<br> &nbsp; &nbsp; PCA0CPM1 = 0xC2;<br> &nbsp; &nbsp; PCA0CPM2 = 0xC2;<br> &nbsp; &nbsp; PCA0L = 0xC0;<br> &nbsp; &nbsp; PCA0H = 0x4F;<br> &nbsp; &nbsp; PCA0CPL0 = 0xFF;<br> &nbsp; &nbsp; PCA0CPL1 = 0xFF;<br> &nbsp; &nbsp; PCA0CPL2 = 0xFF;<br> &nbsp; &nbsp; PCA0CPH0 = 0xFF;<br> &nbsp; &nbsp; PCA0CPH1 = 0xFF;<br> &nbsp; &nbsp; PCA0CPH2 = 0xFF;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;CEX0 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;CEX1 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;CEX2 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x07;<br> &nbsp; &nbsp; XBR1 = 0x43;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> }<br> &nbsp;<br> void get_HB_LB(unsigned int value, unsigned char *HB, unsigned char *LB)<br> {<br> &nbsp; &nbsp; *LB = (unsigned char)(value &amp; 0x00FF);<br> &nbsp; &nbsp; *HB = (unsigned char)((value &amp; 0xFF00) &gt;&gt; 0x08);<br> }<br> <br> <br><br> <br><br> void PWM_0_duty_cycle(unsigned int value)<br> {<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; PCA0CPL0 = lb;<br> &nbsp; &nbsp; PCA0CPH0 = hb;<br> &nbsp; &nbsp; CCF0_bit = 0;<br> }<br> &nbsp;<br> void PWM_1_duty_cycle(unsigned int value)<br> {<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp;<br> &nbsp; &nbsp; PCA0CPL1 = lb;<br> &nbsp; &nbsp; PCA0CPH1 = hb;<br> &nbsp; &nbsp; CCF1_bit = 0;<br> }<br> &nbsp;<br> void PWM_2_duty_cycle(unsigned int value)<br> {<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp;<br> &nbsp; &nbsp; PCA0CPL2 = lb;<br> &nbsp; &nbsp; PCA0CPH2 = hb;<br> &nbsp; &nbsp; CCF2_bit = 0;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-121.png\" alt=\"\" class=\"wp-image-15308\" width=\"705\" height=\"358\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-121.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-121-580x294.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-121-768x390.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This demo uses multi-channel 16-bit PWMs to\nsmoothly change the colours of three RGB LEDs. The LEDs are embedded in a\nleaf-like board from DFRobot called <a href=\"https:\/\/wiki.dfrobot.com\/Clover_Light__SKU_DFR0190_\">clover light<\/a>.\n8-bit PWM is functionally the same as 16-bit PWM. 8-bit PWM has a lower\nresolution but it can be used for high-frequency applications. &nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Red, Blue and Green colours from the LED are mixed in different ratios to form different colours. This mixing of colours is achieved using PWM and so all three PCA channels are used to drive the LEDs. Since PWM is output and not input, all of the PCA pins are set as digital push-pull outputs in the crossbar. PWM pins are labelled as <strong><em>CEXn<\/em><\/strong> pins. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;CEX0 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;CEX1 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;CEX2 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x07;<br> &nbsp; &nbsp; XBR1 = 0x43;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The system clock source is set to 12.5MHz and so one tick is 80ns.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Timing is very important because PWM signals\nare timed outputs with variable pulse widths and so variable or unstable time\nbases would result in odd irregular waveforms. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A clock derived from the system clock or some\nother source is fed to the PCA peripheral and its counter keeps counting. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">PWM is generated by comparing and matching\nthe values of <strong><em>PCA0CPn<\/em><\/strong> and <strong><em>PCA0 <\/em><\/strong>registers. A PWM\noutput pin is set when the contents of PCA0 counter match with the contents of\nPCA0CPn registers and it is reset when the contents of PCA0 counter overflow. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We can optionally load the PCA counter. This\nhas no effect on PWM frequency but it does affect PWM duty cycle. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, the PCA is set to generate three channel PWMs at approximately 46Hz. The PCA clock prescalar is set to 4 and so the 12.25MHz clock is scaled down as per the following calculation:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-122.png\" alt=\"\" class=\"wp-image-15309\" width=\"603\" height=\"170\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-122.png 603w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-122-580x164.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-122-600x170.png 600w\" sizes=\"auto, (max-width: 603px) 100vw, 603px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Since we are using 16-bit resolution PWM in this example, the PWM frequency is calculated as follows:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-123.png\" alt=\"\" class=\"wp-image-15310\" width=\"605\" height=\"144\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-123.png 605w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-123-580x138.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-123-600x144.png 600w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/figure><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0CN = 0x40;<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x02;<br> &nbsp; &nbsp; PCA0CPM0 = 0xC2;<br> &nbsp; &nbsp; PCA0CPM1 = 0xC2;<br> &nbsp; &nbsp; PCA0CPM2 = 0xC2;<br> &nbsp; &nbsp; PCA0L = 0xC0;<br> &nbsp; &nbsp; PCA0H = 0x4F;<br> &nbsp; &nbsp; PCA0CPL0 = 0xFF;<br> &nbsp; &nbsp; PCA0CPL1 = 0xFF;<br> &nbsp; &nbsp; PCA0CPL2 = 0xFF;<br> &nbsp; &nbsp; PCA0CPH0 = 0xFF;<br> &nbsp; &nbsp; PCA0CPH1 = 0xFF;<br> &nbsp; &nbsp; PCA0CPH2 = 0xFF;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that the PCA counter is preloaded with a value and this is just to show that it has no effect on PWM frequency. The <a href=\"https:\/\/www.saleae.com\/\">Saleae Logic<\/a> analyser capture shown below shows the frequency of the three PWM waveforms. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-124.png\" alt=\"\" class=\"wp-image-15311\" width=\"940\" height=\"295\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-124.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-124-580x182.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-124-768x241.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"> According to the datasheet PWM duty cycle for 8-bit and 16-bit PWMs are given as follows:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-125.png\" alt=\"\" class=\"wp-image-15312\" width=\"603\" height=\"169\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-125.png 603w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-125-580x163.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-125-600x169.png 600w\" sizes=\"auto, (max-width: 603px) 100vw, 603px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The following functions can be used to alter the duty cycles of respective PWM channels. These functions take 16-bit input and break the input into two bytes. These bytes are then loaded to respective <em>PCA0CPLn<\/em> and <em>PCA0CPHn<\/em> registers. PWM output is updated with the new values in <em>PCA0CP<\/em> registers upon clearing the capture-compare flag (<em>CCFn<\/em>).&nbsp;&nbsp;&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PWM_0_duty_cycle(unsigned int value)<br> {<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; PCA0CPL0 = lb;<br> &nbsp; &nbsp; PCA0CPH0 = hb;<br> &nbsp; &nbsp; CCF0_bit = 0;<br> }  <br><br> void PWM_1_duty_cycle(unsigned int value)<br> {<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp;<br> &nbsp; &nbsp; PCA0CPL1 = lb;<br> &nbsp; &nbsp; PCA0CPH1 = hb;<br> &nbsp; &nbsp; CCF1_bit = 0;<br> }<br> &nbsp;<br> void PWM_2_duty_cycle(unsigned int value)<br> {<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp;<br> &nbsp; &nbsp; get_HB_LB(value, &amp;hb, &amp;lb);<br> &nbsp;<br> &nbsp; &nbsp; PCA0CPL2 = lb;<br> &nbsp; &nbsp; PCA0CPH2 = hb;<br> &nbsp; &nbsp; CCF2_bit = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the main loop, all three PWM channels are driven using the data from respective lookup tables. These lookup tables contain sinusoidal PWM duty cycle values. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned int i = 0;<br> &nbsp; &nbsp; unsigned char j = 0;<br> &nbsp; &nbsp; unsigned char mode = 1;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 6; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 6; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(0);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 6; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(45);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(j = 0; j &lt; 10; j++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i = 0; i &lt; 32; i++)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_0_duty_cycle(LUT_1[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_1_duty_cycle(LUT_2[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PWM_2_duty_cycle(LUT_3[i]);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(200);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; mode++;<br> &nbsp; &nbsp; &nbsp; &nbsp; if(mode &gt; 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode &nbsp;= 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"536\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-126.png\" alt=\"\" class=\"wp-image-15313\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-126.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-126-580x331.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-126-768x438.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"533\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-127.png\" alt=\"\" class=\"wp-image-15314\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-127.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-127-580x329.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-127-768x436.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - PCA PWM - RGB Clover Light\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/CHn6_LVyuLY?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">PCA in Capture Mode \u2013 TCS3200\nColour Sensor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In many applications, we need to measure\npulse widths and frequencies of signals and in such cases, accurate measurement\ncan be done using a capture module. We can also use external interrupts and\ntimers too but with capture hardware things are far more accurate and precise. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The block diagram below shows the PCA hardware in edge-capture mode. With a defined time base, PCA keeps ticking. When there is an edge capture event, PCA counter values are copied to capture-compare registers. The type of edge to be captured and many other things can be set by tweaking internal registers and it is possible to capture falling and rising edges. Capturing consecutive like edges results in deducing period or frequency while capturing consecutive edges that have different polarities result in deducing pulse width.&nbsp; &nbsp;<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-128.png\" alt=\"\" class=\"wp-image-15316\" width=\"470\" height=\"206\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-128.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-128-580x254.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-128-768x336.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #include \"Waveshare_RGB_LCD.c\"<br> #include \"lcd_print_rgb.c\"<br> &nbsp;<br> #define RED_filter &nbsp; &nbsp; &nbsp;0x00<br> #define BLUE_filter &nbsp; &nbsp; 0x01<br> #define CLEAR_filter &nbsp; &nbsp;0x02<br> #define GREEN_filter &nbsp; &nbsp;0x03<br> &nbsp;<br> #define S2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;P1_4_bit<br> #define S3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; P1_5_bit<br> &nbsp;<br> unsigned long count = 0;<br> unsigned int overflow = 0;<br> unsigned int past_capture = 0;<br> unsigned int current_capture = 0;<br> &nbsp;<br> void PCA_Init(void);<br> void Voltage_Reference_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> unsigned int get_capture_count(void);<br> &nbsp;<br> void PCA0_ISR(void) <br> iv IVT_ADDR_EPCA0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; if(CF_bit)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; overflow++;<br> &nbsp; &nbsp; &nbsp; &nbsp; CF_bit = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(CCF0_bit)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; current_capture = get_capture_count();<br> &nbsp; &nbsp; &nbsp; &nbsp; count = ((overflow &lt;&lt; 16) + (current_capture - past_capture));<br> &nbsp; &nbsp; &nbsp; &nbsp; past_capture = current_capture;<br> &nbsp; &nbsp; &nbsp; &nbsp; overflow = 0x00000;<br> &nbsp; &nbsp; &nbsp; &nbsp; current_capture = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; CCF0_bit = 0;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned long f = 0;<br> &nbsp; &nbsp; unsigned long fr = 0;<br> &nbsp; &nbsp; unsigned long fg = 0;<br> &nbsp; &nbsp; unsigned long fb = 0;<br> &nbsp; &nbsp; unsigned long fc = 0;<br> &nbsp; &nbsp; unsigned char mode = 0;<br> &nbsp;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; RGB_LCD_init();<br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_goto(0, 0);<br> &nbsp; &nbsp; LCD_putstr(\" R% &nbsp;G% &nbsp;B% &nbsp;fC\");<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case RED_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case BLUE_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case CLEAR_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case GREEN_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(100);<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; f = (1020833 \/ ((float)count));<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case RED_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fr = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case BLUE_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fb = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case CLEAR_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fc = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case GREEN_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fg = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; mode++;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(mode &gt; 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fr = (((float)fr \/ (float)fc) * 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fg = (((float)fg \/ (float)fc) * 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fb = (((float)fb \/ (float)fc) * 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(0, 1, fr);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(4, 1, fg);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(8, 1, fb);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_I(12, 1, fc); <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fr &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fg &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fb &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set_RGB(fr, fg, fb);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(400);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0CN = 0x40;<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x01;<br> &nbsp; &nbsp; PCA0CPM0 = 0x11;<br> }<br> &nbsp;<br> void Voltage_Reference_Init(void)<br> {<br> &nbsp; &nbsp; REF0CN = 0x08;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;CEX0 (PCA), &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P1MDOUT = 0xF0;<br> &nbsp; &nbsp; P1SKIP = 0xF0;<br> &nbsp; &nbsp; XBR1 = 0x41;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x10;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Voltage_Reference_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> unsigned int get_capture_count(void)<br> {<br> &nbsp; &nbsp; unsigned char lb = 0x00;<br> &nbsp; &nbsp; unsigned char hb = 0x00;<br> &nbsp; &nbsp; unsigned int cnt = 0x0000;<br> &nbsp;<br> &nbsp; &nbsp; hb = PCA0CPH0;<br> &nbsp; &nbsp; lb = PCA0CPL0;<br> &nbsp;<br> &nbsp; &nbsp; cnt = hb;<br> &nbsp; &nbsp; cnt &lt;&lt;= 8;<br> &nbsp; &nbsp; cnt |= lb;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; return cnt;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-129.png\" alt=\"\" class=\"wp-image-15317\" width=\"432\" height=\"506\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-129.png 576w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-129-555x650.png 555w\" sizes=\"auto, (max-width: 432px) 100vw, 432px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some sensors do not communicate using UART,\nI2C or SPI methods. Such is the case with the TCS3200 colour sensor from TAOS.\nThis sensor is a light-to-frequency output and so we need to convert frequency\noutput to usable data that represents reflected light colour ratios. TCS3200\nhas four types of photodiode arrays for sensing colours, three of which are\nsensitive to red, green and blue colours while a single one consists of a clear\nor no colour filter. Thus, PCA capture is needed to extract colour info. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since capture mode is time-sensitive, the system clock setting must be known. In this example, the system clock is set to 12.25MHz.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The PCA hardware\u2019s channel 0 is set to capture failing edges with PCA counter overflow and PCA channel 0 (<em>CEX0<\/em>) interrupts both enabled and a PCA counter time base source of system clock divided by 12 selected.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0CN = 0x40;<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x01;<br> &nbsp; &nbsp; PCA0CPM0 = 0x11;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With these settings, the tick resolution of the PCA counter is as follows:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-130.png\" alt=\"\" class=\"wp-image-15318\" width=\"604\" height=\"154\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-130.png 604w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-130-580x148.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-130-600x154.png 600w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">So, in theory, the PCA module can measure the following maximum and minimum frequencies as per Nyquist criterion:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-131.png\" alt=\"\" class=\"wp-image-15319\" width=\"605\" height=\"295\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-131.png 605w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-131-580x283.png 580w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Referring to the electrical characteristics of the sensor as shown below, three ranges of frequency outputs can be obtained from it. The first one would not be suitable as the frequency range exceeds the hardware limit of the PCA module as per the settings discussed. The second and third ones are the preferred ones. I have chosen the last one because this range will not overload the PCA module and the readings would be computed quickly. Note with higher frequency settings, the precision of measurement is largely increased but computation and back-calculation times are increased too.&nbsp; <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-132.png\" alt=\"\" class=\"wp-image-15320\" width=\"470\" height=\"177\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-132.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-132-580x218.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-132-768x289.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Now that the theories are established, let us see what happens when falling edges are captured. Whenever a falling edge is detected by the PCA module, the value of the PCA counter is immediately copied to the respective capture-compare register set. Two successive like edges will provide two time captures. The difference between these successive captures results in finding the period. We also need to take into account of any PCA counter overflow that has occurred during these measurements. All these are done inside the PCA interrupt subroutine.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA0_ISR(void) <br> iv IVT_ADDR_EPCA0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; if(CF_bit)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; overflow++;<br> &nbsp; &nbsp; &nbsp; &nbsp; CF_bit = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(CCF0_bit)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; current_capture = get_capture_count();<br> &nbsp; &nbsp; &nbsp; &nbsp; count = ((overflow &lt;&lt; 16) + (current_capture - past_capture));<br> &nbsp; &nbsp; &nbsp; &nbsp; past_capture = current_capture;<br> &nbsp; &nbsp; &nbsp; &nbsp; overflow = 0x00000;<br> &nbsp; &nbsp; &nbsp; &nbsp; current_capture = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; CCF0_bit = 0;<br> &nbsp; &nbsp; }<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the main loop, the photodiode arrays of the sensor are switched by switching the states of its <em>S2<\/em> and <em>S3<\/em> inputs. After switching each filter, the respective frequency reading is extracted and stored. The frequency readings are converted to percentages with respect to the clear filter. These percentages represent the amount of colour reflected with respect to the full visible light spectrum. The <a href=\"https:\/\/www.waveshare.com\/\">Waveshare <\/a><a href=\"https:\/\/www.waveshare.com\/lcd1602-rgb-module.htm\">RGB LCD<\/a>&#8216;s backlight colour tries to mimic the detected colour. This is done by providing RGB data from TCS3200 colour sensor to the PCA9633 IC of the LCD&#8217;s RGB backlight driver.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned long f = 0;<br> &nbsp; &nbsp; unsigned long fr = 0;<br> &nbsp; &nbsp; unsigned long fg = 0;<br> &nbsp; &nbsp; unsigned long fb = 0;<br> &nbsp; &nbsp; unsigned long fc = 0;<br> &nbsp; &nbsp; unsigned char mode = 0;<br> &nbsp;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; RGB_LCD_init();<br> &nbsp; &nbsp; LCD_clear_home();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; LCD_goto(0, 0);<br> &nbsp; &nbsp; LCD_putstr(\" R% &nbsp;G% &nbsp;B% &nbsp;fC\");<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case RED_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case BLUE_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case CLEAR_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case GREEN_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S2 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S3 = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(100);<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; f = (1020833 \/ ((float)count));<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; switch(mode)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case RED_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fr = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case BLUE_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fb = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case CLEAR_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fc = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case GREEN_filter:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fg = f;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; mode++;<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(mode &gt; 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fr = (((float)fr \/ (float)fc) * 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fg = (((float)fg \/ (float)fc) * 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fb = (((float)fb \/ (float)fc) * 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(0, 1, fr);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(4, 1, fg);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_C(8, 1, fb);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print_I(12, 1, fc); <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fr &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fg &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fb &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set_RGB(fr, fg, fb);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mode = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(400);<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-133.png\" alt=\"\" class=\"wp-image-15321\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-133.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-133-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-133-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"531\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-134.png\" alt=\"\" class=\"wp-image-15322\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-134.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-134-580x328.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-134-768x434.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - PCA Waveform Capture  (Frequency) - TCS3200 Colour Sensor\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/U8M_c7FBQAE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">PCA in Frequency Output Mode \u2013 IR\nUART<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the early days of modern\ncell phones, sharing files between two <a href=\"https:\/\/www.youtube.com\/watch?v=JIivZ1MBGCg\">cell phones<\/a> was done\nusing <a href=\"https:\/\/en.wikipedia.org\/wiki\/Infrared_Data_Association\">IrDA<\/a>.\nThere was no Wi-Fi or Bluetooth transfer available at that time. In many\napplications as such, short-range line-of-sight (LOS) wireless communication is\nneeded and for cases, the infrared medium is the best solution and C8051s come\nwith the right hardware for making IR transmitters because of the PCA\nperipheral\u2019s ability to generate frequency outputs. Such outputs can be used to\ngenerate modulation or carrier waves which can then be mixed with data signals\nto make desired bursts of IR data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The block diagram below shows the PCA peripheral in frequency output mode and from this diagram, we can notice that the compare-match principle is used to achieve frequency output.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-135.png\" alt=\"\" class=\"wp-image-15324\" width=\"470\" height=\"168\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-135.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-135-580x207.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-135-768x275.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">IR TX main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT&nbsp;&nbsp; P1_6_bit<br> #define&nbsp;LED_CLK&nbsp;&nbsp;&nbsp; P1_5_bit<br> #define&nbsp;LED_LATCH&nbsp; P1_7_bit<br> &nbsp;<br> #define ADC_res &nbsp; &nbsp;1023.0<br> #define VDD_mv &nbsp; &nbsp; 3200.0<br> &nbsp;<br> #define freq &nbsp; &nbsp; &nbsp; (6125000 \/ 2 \/38000)<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x9C, \/\/ degree<br> &nbsp; 0xC6 &nbsp;\/\/ C<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void UART_Init(void);<br> void ADC_Init(void);<br> void Voltage_Reference_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 11;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned int t = 0;<br> &nbsp; &nbsp; char tmp = 0;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; UART1_Init(1200);<br> &nbsp; &nbsp; ADC1_Init_Advanced(_INTERNAL_REF | _RIGHT_ADJUSTMENT);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; t = (ADC1_Get_Sample(16) * VDD_mv);<br> &nbsp; &nbsp; &nbsp; &nbsp; t \/= 1023.0;<br> &nbsp; &nbsp; &nbsp; &nbsp; t = (((float)t - 776.0) \/ 2.86);<br> &nbsp; &nbsp; &nbsp; &nbsp; value = t;<br> &nbsp; &nbsp; &nbsp; &nbsp; tmp = t;<br> &nbsp; &nbsp; &nbsp; &nbsp; UART1_Write(0xAA);<br> &nbsp; &nbsp; &nbsp; &nbsp; UART1_Write((tmp \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; UART1_Write((tmp % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(400);<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0CN = 0x40;<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x02;<br> &nbsp; &nbsp; PCA0CPM1 = 0x46;<br> &nbsp; &nbsp; PCA0CPH1 = 0x14;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x01;<br> &nbsp; &nbsp; TMR3RLH = 0xFE;<br> }<br> &nbsp;<br> void UART_Init(void)<br> {<br> &nbsp; &nbsp; SCON0 = 0x10;<br> }<br> &nbsp;<br> void ADC_Init(void)<br> {<br> &nbsp; &nbsp; AMX0P = 0x10;<br> &nbsp; &nbsp; AMX0N = 0x11;<br> &nbsp; &nbsp; ADC0CF = 0xF0;<br> &nbsp; &nbsp; ADC0CN = 0x80;<br> }<br> &nbsp;<br> void Voltage_Reference_Init(void)<br> {<br> &nbsp; &nbsp; REF0CN = 0x0F;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;CEX0 (PCA), &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;CEX1 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;TX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;RX0 (UART0), Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x12;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x01;<br> &nbsp; &nbsp; XBR1 = 0x42;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x81;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x80;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; UART_Init();<br> &nbsp; &nbsp; ADC_Init();<br> &nbsp; &nbsp; Voltage_Reference_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">IR RX main.c<\/h4>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; P1_7_bit<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned int value = 0;<br> unsigned char cnt = 0;<br> &nbsp;<br> unsigned char rx_buffer[3] = {0x00, 0x00, 0x00};<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x9C, \/\/ degree<br> &nbsp; 0xC6 &nbsp;\/\/ C<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void UART_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void UART0_ISR(void)<br> iv IVT_ADDR_ES0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; rx_buffer[cnt++] = UART_Read();<br> &nbsp; &nbsp; RI0_bit = 0;<br> }<br> &nbsp;<br> void Timer_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (value % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 10;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = 11;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char tmp = 0x00;<br> &nbsp; &nbsp; unsigned char temp = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; UART1_Init(1200);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(cnt &gt;= 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(rx_buffer[0] == 0xAA)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;temp = (rx_buffer[1] - 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp = (temp * 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;temp = (rx_buffer[2] - 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp += temp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value = tmp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cnt = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void UART_Init(void)<br> {<br> &nbsp; &nbsp; SCON0 = 0x10;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;TX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;RX0 (UART0), Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x10;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x01;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0x90;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; UART_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">IR TX<\/h4>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-136.png\" alt=\"\" class=\"wp-image-15325\" width=\"705\" height=\"350\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-136.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-136-580x288.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-136-768x382.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">IR RX<\/h4>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-137.png\" alt=\"\" class=\"wp-image-15326\" width=\"705\" height=\"362\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-137.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-137-580x297.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-137-768x394.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">IR UART is simply ordinary slow-speed UART\nbut over an infrared (IR) medium. It is slow in terms of the baud rate or the\nnumber of bits transferred per second. Higher baud rates are not suitable for\nwireless mediums. Only a pair of IR LED and IR receiver modules are needed. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To transfer data over an IR medium we need a carrier wave and have it mixed with data to generate a modulated wave that is receivable by the IR receiver module. The idea is rudimentarily shown in the drawing below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-138.png\" alt=\"\" class=\"wp-image-15327\" width=\"470\" height=\"83\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-138.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-138-580x102.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-138-768x136.png 768w\" sizes=\"auto, (max-width: 470px) 100vw, 470px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Like the RF module example,\ntwo C8051F330D boards are used in this example. One of these two is an IR\ntransmitter while the other is an IR receiver. The transmitter is responsible\nfor showing and transmitting its internal temperature data while the receiver\nis responsible for showing this data on its onboard seven-segment\ndisplays.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, let\u2019s see the transmitter side coding. The transmitter uses an IR LED to transmit data via an IR medium. The IRLED anode and cathode pins are connected to the TXD (P0.4) and PCA CEX1 (P0.1) pins respectively. Connecting the IR LED this way automatically ensures modulation. The TXD pin is responsible for sending data while the PCA pin ensures transmission of carrier wave.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;CEX1 (PCA), &nbsp;Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;TX0 (UART0), Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x12;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P1SKIP = 0xE0;<br> &nbsp; &nbsp; XBR0 = 0x01;<br> &nbsp; &nbsp; XBR1 = 0x42;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The system clock is set to 6.125MHz by scaling the internal oscillator. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x81;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Let us now see the settings that have let us output 38kHz carrier wave from the PCA module. According to the device datasheet, the following formula should be used to generate frequency output:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-139.png\" alt=\"\" class=\"wp-image-15328\" width=\"606\" height=\"72\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-139.png 606w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-139-580x69.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-139-600x72.png 600w\" sizes=\"auto, (max-width: 606px) 100vw, 606px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">According to the settings, the PCA clock has a frequency of:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-140.png\" alt=\"\" class=\"wp-image-15329\" width=\"600\" height=\"145\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-140.png 600w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-140-580x140.png 580w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">and the frequency output from the PCA channel is calculated to be: <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-141.png\" alt=\"\" class=\"wp-image-15330\" width=\"608\" height=\"72\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-141.png 608w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-141-580x69.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-141-600x72.png 600w\" sizes=\"auto, (max-width: 608px) 100vw, 608px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">This ensures the required 38KHz carrier wave.&nbsp; <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0CN = 0x40;<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x02;<br> &nbsp; &nbsp; PCA0CPM1 = 0x46;<br> &nbsp; &nbsp; PCA0CPH1 = 0x14;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The PCA interrupts are not needed and are optional.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All that is left at this stage on the transmitter side is the main code. Here, we can see that the UART is set with a 1200 baud rate using MikroC\u2019s built-in UART library. The communication speed is slow but it is set so because of a trade-off between speed and reliability.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned int t = 0;<br> &nbsp; &nbsp; char tmp = 0;<br> &nbsp;<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; UART1_Init(1200);<br> &nbsp; &nbsp; ADC1_Init_Advanced(_INTERNAL_REF | _RIGHT_ADJUSTMENT);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; t = (ADC1_Get_Sample(16) * VDD_mv);<br> &nbsp; &nbsp; &nbsp; &nbsp; t \/= 1023.0;<br> &nbsp; &nbsp; &nbsp; &nbsp; t = (((float)t - 776.0) \/ 2.86);<br> &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value = t;<br> &nbsp; &nbsp; &nbsp; &nbsp; tmp = t;<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; UART1_Write(0xAA);<br> &nbsp; &nbsp; &nbsp; &nbsp; UART1_Write((tmp \/ 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; UART1_Write((tmp % 10) + 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(400);<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that, here, the internal temperature\nsensor is used as a source of data to be transmitted. The main loop reads this\nsensor, displays the temperature and sends the temperature to the C8051F330D\nboard nearby. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To be able to use the internal temperature sensor (ADC channel 16), we need to use the internal reference. The following graph shows the relation between the output voltage from the sensor and temperature.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-142.png\" alt=\"\" class=\"wp-image-15331\" width=\"414\" height=\"302\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-142.png 827w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-142-580x423.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-142-768x560.png 768w\" sizes=\"auto, (max-width: 414px) 100vw, 414px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The equation in this graph gives voltage as a function of temperature. However, we need temperature data from voltage since we can measure voltage from ADC and certainly not temperature directly. Thus, the equation above needs rearrangement.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-143.png\" alt=\"\" class=\"wp-image-15332\" width=\"600\" height=\"229\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-143.png 600w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-143-580x221.png 580w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">These have been\nused inside the main loop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lastly, temperature data is sent using UART in the following packet format:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-144.png\" alt=\"\" class=\"wp-image-15333\" width=\"346\" height=\"80\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-144.png 691w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-144-580x133.png 580w\" sizes=\"auto, (max-width: 346px) 100vw, 346px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The code for the receiver side is very easy\nbecause the IR receiver module internally completes the demodulation task and\nprovide raw UART output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Firstly, data received by the UART is received using the interrupt method. Received serial data are stored in an array buffer called <em>rx_buffer<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void UART0_ISR(void)<br> iv IVT_ADDR_ES0<br> ilevel 0<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; rx_buffer[cnt++] = UART_Read();<br> &nbsp; &nbsp; RI0_bit = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since three bytes of data are to be received, the main code waits for three-byte counts before processing the received data. Firstly, the preamble header is looked for. If the first byte matches with the expected header (0xAA) then the next two bytes are assumed to contain temperature data. After extracting the bytes, the temperature data received is shown on the onboard seven-segment display. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; unsigned char tmp = 0x00;<br> &nbsp; &nbsp; unsigned char temp = 0x00;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; UART1_Init(1200);<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(cnt &gt;= 3)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(rx_buffer[0] == 0xAA)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;temp = (rx_buffer[1] - 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp = (temp * 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;temp = (rx_buffer[2] - 0x30);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp += temp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;value = tmp;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cnt = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"528\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-145.png\" alt=\"\" class=\"wp-image-15334\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-145.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-145-580x326.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-145-768x431.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"530\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-146.png\" alt=\"\" class=\"wp-image-15335\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-146.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-146-580x327.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-146-768x433.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - PCA Frequency Output - Wireless (IR) UART Data Transfer\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/YV_2f-8bnIs?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Software PWM \u2013 Servo Motor Control<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes we run out of PWM channels and in some cases, the PWM pins may have alternative use in a project. For a tiny microcontroller like the C8051F330D, both cases are very likely. In such scenarios, we can code software PWMs just like what we do with software-based communications like software-based I2C and software-based SPI. Any GPIO pin can be used for software PWM and that is the biggest advantage. There are a few limitations though with this concept. Firstly, some coding is needed and secondly, software PWM techniques are not fast and less accurate not to mention the limited options it offers, unlike hardware PWM.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-147.png\" alt=\"\" class=\"wp-image-15336\" width=\"704\" height=\"245\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-147.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-147-580x202.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-147-768x267.png 768w\" sizes=\"auto, (max-width: 704px) 100vw, 704px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define LED_DOUT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_6_bit<br> #define LED_CLK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_5_bit<br> #define LED_LATCH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P1_7_bit<br> &nbsp;<br> #define INC_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_4_bit<br> #define DEC_SW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P1_3_bit<br> &nbsp;<br> #define duty_min &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5<br> #define duty_max &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 25<br> #define counts &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 240<br> &nbsp;<br> unsigned char i = 0;<br> register unsigned char val = 0;<br> unsigned char count = 0;<br> unsigned char duty_cycle_1 = duty_min;<br> unsigned char duty_cycle_2 = duty_max;<br> &nbsp;<br> const unsigned char code segment_code[12] =<br> {<br> &nbsp; 0xC0, \/\/ 0<br> &nbsp; 0xF9, \/\/ 1<br> &nbsp; 0xA4, \/\/ 2<br> &nbsp; 0xB0, \/\/ 3<br> &nbsp; 0x99, \/\/ 4<br> &nbsp; 0x92, \/\/ 5<br> &nbsp; 0x82, \/\/ 6<br> &nbsp; 0xF8, \/\/ 7<br> &nbsp; 0x80, \/\/ 8<br> &nbsp; 0x90, \/\/ 9<br> &nbsp; 0x7F, \/\/ .<br> &nbsp; 0xBF &nbsp;\/\/ -<br> };<br> &nbsp;<br> const unsigned char code display_pos[4] =<br> {<br> &nbsp; 0xF7, \/\/1st Display<br> &nbsp; 0xFB, \/\/2nd Display<br> &nbsp; 0xFD, \/\/3rd Display<br> &nbsp; 0xFE &nbsp;\/\/4th Display<br> };<br> &nbsp;<br> void PCA_Init(void);<br> void Timer_Init(void);<br> void Port_IO_Init(void);<br> void Oscillator_Init(void);<br> void Interrupts_Init(void);<br> void Init_Device(void);<br> void write_74HC595(unsigned char send_data);<br> void segment_write(unsigned char disp, unsigned char pos);<br> &nbsp;<br> void Timer_2_ISR(void)<br> iv IVT_ADDR_ET2<br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; count++;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(count &lt;= counts)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(count &lt;= duty_cycle_1)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_0_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_0_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(count &lt;= duty_cycle_2)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; count = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; P0_2_bit = ~P0_2_bit;<br> &nbsp; &nbsp; TF2H_bit = 0;<br> }<br> &nbsp;<br> void Timer_3_ISR(void)<br> iv IVT_ADDR_ET3<br> ilevel 1<br> ics ICS_AUTO<br> {<br> &nbsp; &nbsp; switch(i)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; case 0:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (duty_cycle_1 \/ 1000);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 1:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((duty_cycle_1 % 1000) \/ 100);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 2:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = ((duty_cycle_1 % 100) \/ 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; case 3:<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = (duty_cycle_1 % 10);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; segment_write(val, i);<br> &nbsp;<br> &nbsp; &nbsp; i++;<br> &nbsp;<br> &nbsp; &nbsp; if(i &gt; 3)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp;i = 0;<br> &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; TMR3CN &amp;= 0x7F;<br> }<br> &nbsp;<br> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1++;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2--;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1--;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(duty_cycle_1 &gt;= duty_max)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1 = duty_max;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2 = duty_min;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(duty_cycle_1 &lt;= duty_min)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1 = duty_min;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2 = duty_max;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> }<br> &nbsp;<br> void PCA_Init(void)<br> {<br> &nbsp; &nbsp; PCA0MD &amp;= ~0x40;<br> &nbsp; &nbsp; PCA0MD = 0x00;<br> }<br> &nbsp;<br> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR2CN = 0x04;<br> &nbsp; &nbsp; TMR2RLL = 0x99;<br> &nbsp; &nbsp; TMR2RLH = 0xFF;<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> void Port_IO_Init(void)<br> {<br> &nbsp; &nbsp; \/\/ P0.0 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.1 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.2 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P0.3 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.4 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.5 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.6 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P0.7 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp;<br> &nbsp; &nbsp; \/\/ P1.0 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.1 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.2 &nbsp;- &nbsp;Unassigned, &nbsp;Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.3 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.4 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Open-Drain, Digital<br> &nbsp; &nbsp; \/\/ P1.5 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.6 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp; &nbsp; \/\/ P1.7 &nbsp;- &nbsp;Skipped, &nbsp; &nbsp; Push-Pull, &nbsp;Digital<br> &nbsp;<br> &nbsp; &nbsp; P0MDOUT = 0x07;<br> &nbsp; &nbsp; P1MDOUT = 0xE0;<br> &nbsp; &nbsp; P0SKIP = 0x07;<br> &nbsp; &nbsp; P1SKIP = 0xF8;<br> &nbsp; &nbsp; XBR1 = 0x40;<br> }<br> &nbsp;<br> void Oscillator_Init(void)<br> {<br> &nbsp; &nbsp; OSCICN = 0x82;<br> }<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0xA0;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }<br> &nbsp;<br> void Init_Device(void)<br> {<br> &nbsp; &nbsp; PCA_Init();<br> &nbsp; &nbsp; Timer_Init();<br> &nbsp; &nbsp; Port_IO_Init();<br> &nbsp; &nbsp; Oscillator_Init();<br> &nbsp; &nbsp; Interrupts_Init();<br> }<br> &nbsp;<br> void write_74HC595(unsigned char send_data)<br> {<br> &nbsp; &nbsp; signed char clks = 8;<br> &nbsp;<br> &nbsp; &nbsp; while(clks &gt; 0)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if((send_data &amp; 0x80) == 0x00)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LED_DOUT = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; send_data &lt;&lt;= 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; clks--;<br> &nbsp; &nbsp; &nbsp; &nbsp; LED_CLK = 1;<br> &nbsp; &nbsp; }<br> }<br> &nbsp;<br> void segment_write(unsigned char disp, unsigned char pos)<br> {<br> &nbsp; &nbsp; LED_LATCH = 0;<br> &nbsp; &nbsp; write_74HC595(segment_code[disp]);<br> &nbsp; &nbsp; write_74HC595(display_pos[pos]);<br> &nbsp; &nbsp; LED_LATCH = 1;<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-148.png\" alt=\"\" class=\"wp-image-15337\" width=\"705\" height=\"343\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-148.png 940w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-148-580x282.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-148-768x373.png 768w\" sizes=\"auto, (max-width: 705px) 100vw, 705px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Explanation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, software PWM is used to drive two servo motors. Firstly, let us examine the servo motor signal timing diagram given below. From this diagram, it is evident that to drive a servo motor we need a PWM signal with a 20ms time period (50Hz) and 5 \u2013 10% duty cycle. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-149.png\" alt=\"\" class=\"wp-image-15338\" width=\"269\" height=\"354\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-149.png 538w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-149-495x650.png 495w\" sizes=\"auto, (max-width: 269px) 100vw, 269px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">To code software PWM, all we need are GPIOs and a timer. Since a timer is needed, we have to be careful about the system clock setting. Here, the system clock is set to 12.25MHz, i.e., one system clock tick is about 80ns.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-151.png\" alt=\"\" class=\"wp-image-15340\" width=\"603\" height=\"218\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-151.png 603w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-151-580x210.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-151-600x218.png 600w\" sizes=\"auto, (max-width: 603px) 100vw, 603px\" \/><\/figure><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\"> void Timer_Init(void)<br> {<br> &nbsp; &nbsp; TMR2CN = 0x04;<br> &nbsp; &nbsp; TMR2RLL = 0x99;<br> &nbsp; &nbsp; TMR2RLH = 0xFF;<br> &nbsp; &nbsp; TMR3CN = 0x04;<br> &nbsp; &nbsp; TMR3RLL = 0x02;<br> &nbsp; &nbsp; TMR3RLH = 0xFC;<br> }<br> &nbsp;<br> &nbsp;<br> void Interrupts_Init(void)<br> {<br> &nbsp; &nbsp; IE = 0xA0;<br> &nbsp; &nbsp; EIE1 = 0x80;<br> }  <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Inside the Timer 2 interrupt, a variable named <em>count<\/em> is incremented from 0 to 240. This variable defines the timer period. Since the variable resets after every 240 counts, the PWM period is calculated to be:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-150.png\" alt=\"\" class=\"wp-image-15339\" width=\"602\" height=\"58\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-150.png 602w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-150-580x56.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-150-600x58.png 600w\" sizes=\"auto, (max-width: 602px) 100vw, 602px\" \/><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As stated, a servo motor is typically run using pulses having a 20ms time period and here we achieved just that, although not exactly 20ms. This difference is kept intentionally to balance off any tolerance in timing. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> #define duty_min &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5<br> #define duty_max &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 25<br> #define counts &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 240<br> &nbsp;<br> ....<br> &nbsp;<br> void Timer_2_ISR(void)<br> iv IVT_ADDR_ET2<br> ilevel 0 <br> ics ICS_AUTO <br> {<br> &nbsp; &nbsp; count++;<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; if(count &lt;= counts)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(count &lt;= <a>duty_cycle_1<\/a>)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_0_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_0_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(count &lt;= duty_cycle_2)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 1;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; else<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; P0_1_bit = 0;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; else<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; count = 0;<br> &nbsp; &nbsp; }<br> &nbsp; &nbsp; P0_2_bit = ~P0_2_bit;<br> &nbsp; &nbsp; TF2H_bit = 0;<br> } <\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Variables named <em>duty_cycle_1<\/em> and <em>duty_cycle_2<\/em>\nare used to control the duty cycles of two PWM channels. From 0 count to the\nvalue stored in these variables, respective GPIOs are set high and when the\ncount variable exceeds these values, respective GPIOs are set low. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the main, two onboard push buttons connected with pins P1.3 and P1.4 are pressed to change the duty cycle and the corresponding servo rotations are altered. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> void main(void)<br> {<br> &nbsp; &nbsp; Init_Device();<br> &nbsp; &nbsp; <br> &nbsp; &nbsp; while(1)<br> &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; if(INC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1++;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2--;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(DEC_SW == 0)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delay_ms(60);<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1--;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2++;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(duty_cycle_1 &gt;= duty_max)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1 = duty_max;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2 = duty_min;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; &nbsp; &nbsp; <br> &nbsp; &nbsp; &nbsp; &nbsp; if(duty_cycle_1 &lt;= duty_min)<br> &nbsp; &nbsp; &nbsp; &nbsp; {<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_1 = duty_min;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; duty_cycle_2 = duty_max;<br> &nbsp; &nbsp; &nbsp; &nbsp; }<br> &nbsp; &nbsp; };<br> } <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demo<\/h3>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"531\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-152.png\" alt=\"\" class=\"wp-image-15341\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-152.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-152-580x328.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-152-768x434.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"522\" src=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-153.png\" alt=\"\" class=\"wp-image-15342\" srcset=\"https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-153.png 939w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-153-580x322.png 580w, https:\/\/embedded-lab.com\/blog\/wp-content\/uploads\/2023\/05\/image-153-768x427.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-embed-youtube aligncenter wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"SiLabs C8051F330 - Software PWM - Servo Motor Control\" width=\"860\" height=\"484\" src=\"https:\/\/www.youtube.com\/embed\/ynxU_R_mW4A?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">Epilogue<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In conclusion, SiLabs C8051 microcontrollers\nhave proven to be a versatile and powerful choice for embedded systems\ndevelopment although at present times ARM microcontrollers with advanced\nfeatures like Wi-Fi, BLE and other features are dominant players. The rich\nfeature set of C8051s, combined with robust performance and low power\nconsumption, make them a preferred option for a wide range of small and\nmedium-scale applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We explored some key aspects of SiLabs C8051\nmicrocontrollers, including their internals, features, and other things. I am\nimpressed by the analogue and digital capabilities that enabled seamless\ninterfacing with various sensors and devices. Apart from the hardware side, the\nsoftware tools are also tweaked for rapid development.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As technology continues to advance, SiLabs\nremains committed to enhancing its microcontroller offerings, providing\ncontinuous support and innovation to developers worldwide. With a vast\necosystem and a dedicated community, the possibilities for leveraging the power\nof SiLabs C8051 microcontrollers are limitless.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In conclusion, SiLabs C8051 microcontrollers\nare a dependable and flexible solution for embedded systems development. Their\noutstanding features, comprehensive development tools, and energy-efficient\ndesign make them a compelling choice for any project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Although it is irrelevant\nhere, this document has been fine-tuned with the help of <a href=\"https:\/\/chat.openai.com\/\">ChatGPT<\/a> and <a href=\"https:\/\/app.grammarly.com\/\">Grammarly<\/a>. These two platforms have saved\na lot of time while checking and editing this document. I, humbly, give credit\nto developers who are also programmers like me and worked on such platforms. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Code Examples and Libraries used in this tutorial can be downloaded from <a href=\"https:\/\/github.com\/sshahryiar\/SiLabs-C8051F330-Microcontroller-Tutorial\">here<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All demo videos of this tutorial can be found in this <a href=\"https:\/\/youtube.com\/playlist?list=PL-EErZRpDPIWmbv_A1gEZgIDU9Sjo9lZJ\">Youtube playlist.<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Happy coding.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Author: Shawon M. Shahryiar<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.youtube.com\/c\/sshahryiar\">https:\/\/www.youtube.com\/c\/sshahryiar<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/sshahryiar\">https:\/\/github.com\/sshahryiar<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.facebook.com\/groups\/microarena\">https:\/\/www.facebook.com\/groups\/microarena<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.facebook.com\/microarena\"><em>https:\/\/www.facebook.com\/microarena<\/em><\/a><em> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>26.05.2023<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In a world where upgrades and advancements are constant, it is easy to overlook older technology in favour of newer, more advanced options. However, the case of 8051 microcontrollers defies this trend. Despite being considered relics of the past, there is still a significant demand for these microcontrollers. Manufacturers have revitalized the proven 8051 architecture by incorporating modern features such as ADCs and communication modules, transforming them into powerful, reliable and versatile devices. Silicon Laboratories (SiLabs) is an American semiconductor-manufacturing company, similar to Microchip and STMicroelectronics. They are renowned for producing a wide range of semiconductor components, including both 8<\/p>\n","protected":false},"author":5,"featured_media":15171,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1466],"tags":[1646,1722,1753,1754,354,9,1757,238,1060,1755,1756,501],"class_list":["post-15170","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-8-bit-microcontroller","tag-1722","tag-c8051","tag-c8051f330","tag-microcontroller","tag-mikroc","tag-mikroc-for-8051","tag-mikroelektronika","tag-silabs","tag-silicon-laboratories","tag-silicon-labs","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/15170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/comments?post=15170"}],"version-history":[{"count":65,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/15170\/revisions"}],"predecessor-version":[{"id":15402,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/posts\/15170\/revisions\/15402"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/media\/15171"}],"wp:attachment":[{"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/media?parent=15170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/categories?post=15170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embedded-lab.com\/blog\/wp-json\/wp\/v2\/tags?post=15170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}