
ECE 3567 Microcontrollers Lab Lecture #2 – The Microcontroller & Embedded C Programming Autumn 2019 Dr. Gregg Chapman 1 Numbering The Hexadecimal Number System. Hexadecimal Values of Bit Positions (Used to read or write register values) Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 1 1 0 0 0 0 0 0 0xC0 0 0 0 0 0 0 1 1 0x03 1 1 0 0 0 1 1 1 0xC7 0 0 0 0 1 1 1 1 0x0F 1 1 1 1 0 0 0 0 0xF0 0 0 0 0 0 0 0 0 0x00 0 1 0 1 0 1 0 1 0x55 1 0 1 0 1 0 1 0 0xAA 1 1 1 1 1 1 1 1 0xFF Registers – Bit numbering WE USE: 7 6 5 4 3 2 1 0 Hexadecimal Values of Bit Positions Don’t get Bit by Bit Numbering Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 0 0 0 0 0 0 0 1 0x01 0 0 0 0 0 0 1 0 0x02 0 0 0 0 0 1 0 0 0x04 0 0 0 0 1 0 0 0 0x08 0 0 0 1 0 0 0 0 0x10 0 0 1 0 0 0 0 0 0x20 0 1 0 0 0 0 0 0 0x40 1 0 0 0 0 0 0 0 0x80 Register Terminology • Note that each 4-bit nibble can be converted to a single Hexadecimal character. • Register contents are always expressed in hexadecimal values. Registers 0000 0100 1110 0000 0x0 , or 0h 0x4 , or 4h 0xE , or Eh 0x0 , or 0h • Example of 4-bit binary values converted to a single Hexadecimal character. This 16-bit register value would be shown as: 0x04E0 Data Types C Programming Language ! ! ! ! √ √ X X √ √ X X X Data Types Processor Dependent!! MSP430 Series Microcontrollers √ √ ! ! √ √ Variable Declaration Modifiers • const – single value at runtime and cannot be altered • volatile – value can be altered anywhere in code (global) • extern – declaration is in another file, but can be used in current file • static – value can be altered only within the current file Examples: volatile unsigned int delay; extern volatile unsigned char i, j, k; static int counter; const int x = 123; Constant Declarations There are “constant” variables: const int x = 0x1234; Constant numbers are usually defined with the compiler directive: #define RED 0x11 C Operations (for reference) C Operations C Operations C Operations MOST Important Operators in Embedded C Programming ! Used to CLEAR Bits Used to TOGGLE Bits Used to SET Bits Used to INVERT ALL Bits HOW TO SET A BIT IN A REGISTER In C programming, the | character is a BITWISE OR NOTE THAT: 0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1 By BITWISE ORing a register with 1s in the bits you want to SET, and 0s in the bits that you want to preserve, YOU ONLY SET THE BITS AT LOCATIONS WHERE THERE ARE A ONES IN THE BYTE USED TO OPERATE ON THE REGISTER HOW TO SET A BIT IN A REGISTER EXAMPLE 1: RESIGTER is: 0000 0000 SET Bit 4 REGISTER |= 0x10; 0x10 = 0001 0000 (0000 0000) | (0001 0000) = (0001 0000) You have SET Bit 4 HOW TO SET A BIT IN A REGISTER EXAMPLE 2: RESIGTER is: 1010 1010 SET Bit 2 REGISTER |= 0x04; 0x04 = 0000 0100 (1010 1010) | (0000 0100) = (1010 1110) You have SET Bit 2 HOW TO SET A BIT IN A REGISTER EXAMPLE 3: RESIGTER is: ???? ???? SET Bit 7 REGISTER |= 0x80; 0x80 = 1000 0000 (???? ????) | (1000 0000) = (1??? ????) You have insured that Bit 7 is SET regardless of the other bit values. HOW TO SET A BIT IN A REGISTER EXAMPLE 4: RESIGTER is: 1111 0000 SET Bits 0 and 1 REGISTER |= 0x03; 0x03 = 0000 0011 (1111 0000) | (0000 0011) = (1111 0011) You have SET bits 0 and 1. HOW TO CLEAR A BIT IN A REGISTER In C programming, the & character is a BITWISE AND NOTE THAT: 0 & 1 = 0 1 & 1 = 1 By BITWISE ANDing a register with 1s in the bits you want to preserve, and 0s in the bits that you want to clear, YOU ONLY CLEAR THE BITS AT LOCATIONS WHERE THERE ARE A ZEROS IN THE BYTE USED TO OPERATE ON THE REGISTER HOW TO CLEAR A BIT IN A REGISTER EXAMPLE 1: RESIGTER is: 1111 1111 Clear Bit 4 REGISTER &= 0xEF; 0xEF = 1110 1111 (1111 1111) & (1110 1111) = (1110 1111) You have CLEARED Bit 4 HOW TO CLEAR A BIT IN A REGISTER EXAMPLE 2: RESIGTER is: 1010 1010 Clear Bit 3 REGISTER &= 0xF7; 0xF7 = 1111 0111 (1010 1010) & (1111 0111) = (1010 0010) You have CLEARED Bit 3 HOW TO CLEAR A BIT IN A REGISTER EXAMPLE 3: RESIGTER is: 0000 0000 Clear Bit 0 REGISTER &= 0xFE; 0xFE = 1111 1110 (0000 0000) & (1111 1110) = (0000 0000) You have insured that Bit 0 is cleared HOW TO CLEAR A BIT IN A REGISTER EXAMPLE 4: RESIGTER is: ???? ???? Clear Bit 7 REGISTER &= 0x7F; 0x7F = 0111 1111 (???? ????) & (0111 1111) = (0??? ????) You have insured that bit 7 is cleared, regardless of the other bit values HOW TO CLEAR A BIT IN A REGISTER EXAMPLE 5: RESIGTER is: 1111 0000 Clear Bits 6 and 5 REGISTER &= 0x9F; 0x9F = 1001 1111 (1111 0000) & (1001 1111) = (1001 0000) You have cleared Bits 6 and 5 HOW TO CLEAR A BIT IN A REGISTER EXAMPLE 6: Alternate Notation: RESIGTER is: 1111 0000 Clear Bits 6 and 5 REGISTER &= ~(BIT6 & BIT5); (BIT6 & BIT5) = (0100 0000) & (0010 0000) = 0110 0000 ~(BIT6 and BIT5) = 1001 1111 (1111 0000) & (1001 1111) = (1001 0000) You have cleared bits 6 and 5 TI Method of Setting BIT Fields of Different Sizes 2*0x1000u DEFINES THE FIRST BIT OF THE FIELD TO BE USED #define BIT0 (0x0001) STEPS: #define BIT1 (0x0002) 1. Convert this number to BINARY #define BIT2 (0x0004) #define BIT3 (0x0008) 2. Place the number in the register with #define BIT4 (0x0010) the Least Significant Bit of the field #define BIT5 (0x0020) defined by this value (See Table) #define BIT6 (0x0040) #define BIT7 (0x0080) EXAMPLES: 0010 0000 0000 0000 #define BIT8 (0x0100) #define BIT9 (0x0200) 9*0x0020u: #define BIT10 (0x0400) 0000 0001 0010 0000 #define BIT11 (0x0800) #define BIT12 (0x1000) 7*0x2000u: #define BIT13 (0x2000) 1110 0000 0000 0000 #define BIT14 (0x4000) #define BIT15 (0x8000) 3*0x0040u: 0000 0000 1100 0000 Other Ways to Express the Bit Patterns 0000 1000 = 0x08 = BIT3 Because a #included header file msp430fr6989.h contains: This is HEX not Binary #define BIT0 (0x0001) 1111 0111 = 0xF7 = ~0x08 = ~BIT3 #define BIT1 (0x0002) #define BIT2 (0x0004) #define BIT3 (0x0008) #define BIT4 (0x0010) #define BIT5 (0x0020) #define BIT6 (0x0040) #define BIT7 (0x0080) #define BIT8 (0x0100) #define BIT9 (0x0200) #define BITA (0x0400) #define BITB (0x0800) #define BITC (0x1000) #define BITD (0x2000) #define BITE (0x4000) #define BITF (0x8000) NOTE: msp430fr6989.h is #included in driverlib.h Toggling Bits Compliment Bit 0 of register P1OUT P1OUT ^= BIT0; // P1OUT XOR 0x0001 inverts BIT0 only (NOTE: This is the Bitwise Exclusive OR operator: A ZERO retains the bit value of all the positions that are zero. A ONE INVERTS the positions that are 1. Since BIT0 is #defined as 0x0001 it is the only bit complimented. Pretty Cool (not to mention useful). a b XOR 0 0 0 0 1 1 1 0 1 1 1 0 31 Programming Compiler Directives (from Lecture #1) • #include – append contents of the external file • #define – text substitution for a constant, can assign a numeric value • #pragma – directs compiler to ignore multiple declarations of the same entity • #ifdef – begin conditional compilation, paired with #endif • #ifndef – define only if it hasn’t already been defined • #typedef – defines an alias name or new type Function Prototypes void funct1(); void funct1(void); void funct2(unsigned int); unsigned int funct3(void); unsigned int funct4(char); unsigned int funct5(char, unsigned int); NOTE: I put all function prototypes in a separate header file called 3567.h Functions Called by Value Functions Called by Reference 2 Local Variables • Declared inside functions • Are not preserved when the execution returns form the function unless returned. void delay_cycles(unsigned int x) { unsigned int a; a = x; while (a >= 0) { a--; } return; } Function with Local Variables NOTE: You can return a local variable if the function prototype has a returned parameter Loops in Embedded C Use while loops if possible FOR LOOP WHILE LOOP Also a do-while which tests at end. Not used much. if-else if-else or switch ? if-else if-else or switch ? • Use switch statements, for more than 3 conditions AND the values are constants. The cross-compiler will make a jump table (which is way more efficient than multiple tests). • Use if-else if-else if the cases are Boolean or logical expressions. • In general, most cross-compilers are more efficient with switch. • switch is much more readable (easy to understand), IMHO • For a low number of cases, the difference is negligible. How to handle external delays of unknown duration NEVER just wait: (assumes no Watchdog Timer) TAOCTL0 |+= CCIE; // Enable process while(CCIF == 0); // CODE HANGS HERE if no event Value = TAOR; // Read Result How to handle external delays of unknown duration Method 1: Rely on a Watchdog Timeout TAOCTL0 |+= CCIE; // Enable process WDTCTL = WDTPW+WDTCNTCL; //Refresh the Watchdog timer while(CCIF == 0); // Watchdog timer could timeout if enabled Value = TAOR; // Read Result How to handle external delays of unknown duration Method 2: Use a down-counter to prevent hanging: timeout = 0x100; while (timeout > 0) { timeout--; if (flag == 1) //external event occurred break; } How to handle external delays of unknown duration Method 3a: Method 3b: MEASURE the worst-case MEASURE the worst-case latency and add as delay latency and add NOPs count (slow process) (short, fast process) // enable process // enable process TAOCTL0 |+= CCIE; TAOCTL0 |+= CCIE; delay(2000); __no_operation(); // TI NOP macro if (CCIF == 1) // flag checking __no_operation(); // TI NOP macro { __no_operation(); // TI NOP macro Value = TAOR; __no_operation(); // TI NOP macro } __no_operation(); // TI NOP macro Value = TAOR; Every Cross-Compiler has “Gotchas” Example from Code Composer Studio: void delay(unsigned long delay_count) void delay(unsigned long delay_count) { { while(delay_count > 1) while(delay_count > 1) { { delay_count--; delay_count--; } } __no_operation(); // TI NOP macro return; return; } } Never put a return directly after a loop.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages70 Page
-
File Size-