diff --git a/content/en/posts/csci-1200/hw-2/index.md b/content/en/posts/csci-1200/hw-2/index.md index 7114389..595e912 100644 --- a/content/en/posts/csci-1200/hw-2/index.md +++ b/content/en/posts/csci-1200/hw-2/index.md @@ -597,9 +597,9 @@ classDiagram void exportDrivers(const std::string &filename, const std::vector &drivers) { //... std::ofstream ofs(filename); - - for (const auto &d : drivers) { - + for (int i = 0; i < (int)drivers.size(); i++) { - + const Driver &d = drivers[i]; + - for (const auto &d : drivers) { + + for (int i = 0; i < (int)drivers.size(); i++) { + + const Driver &d = drivers[i]; ofs << d.toFileString() << "\n"; } ofs.close(); diff --git a/content/en/posts/engr-2350/lab01/index.md b/content/en/posts/engr-2350/lab01/index.md new file mode 100644 index 0000000..002af05 --- /dev/null +++ b/content/en/posts/engr-2350/lab01/index.md @@ -0,0 +1,1103 @@ +--- +title: ENGR 2350 - Laboratory 1 - Digital Input/Output (GPIO) +subtitle: +date: 2025-02-10T10:10:37-05:00 +lastmod: 2025-02-10T10:10:37-05:00 +slug: engr-2350-lab-01 +draft: false +author: + name: James + link: https://www.jamesflare.com + email: + avatar: /site-logo.avif +description: +keywords: +license: +comment: true +weight: 0 +tags: + - C + - Programming + - RPI + - ENGR 2350 + - Lab +categories: + - Programming + - Electrical Engineering +collections: + - ENGR 2350 +hiddenFromHomePage: false +hiddenFromSearch: false +hiddenFromRss: false +hiddenFromRelated: false +summary: +resources: + - name: featured-image + src: featured-image.jpg + - name: featured-image-preview + src: featured-image-preview.jpg +toc: true +math: false +lightgallery: true +password: +message: +repost: + enable: false + url: + +# See details front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter +--- + + + +## Laboratory Description + +In this lab, simple digital inputs are used to program the TI-RSLK to drive in a desired pattern composed of independent segments: + +1. Drive and turn left 90° +2. Drive and turn left 45° +3. Drive forward +4. Drive and turn right 45° +5. Drive and turn right 90° +6. Stop for 1 second. + +The bumper buttons on the car will be used to input each sequential step while a breadboard wired slide switch will cause the inputted pattern to execute and/or stop. One breadboard wired pushbutton is used to delete the last step inputted while a second wired pushbutton will delete all steps inputted. A BiColor LED will provide indication of if the pattern is running (GREEN), the pattern is complete (RED) or the program is waiting for user input (OFF). + +### Laboratory Goals + +This laboratory is designed to further a student's understanding of: + +* The Code Composer Studio (CCS) Integrated Development Environment +* Programming the MSP432P401R microcontroller, +* The implementation and use of inputs and outputs, +* The development of modular C programs towards producing a function system, and +* The functionality of the TI Robotics System Learning Kit (TI-RSLK). + +### Preparation + +Students should complete Activities 1-5 prior to starting this laboratory. *A good understanding of the tasks in Activity 5 is essential for this laboratory.* + +### Hardware and Tools + +- TI-RSLK Robotic Car +- Breadboard +- Components (provided): + - 2x Pushbutton + - 1x Slideswitch + - 1x BiColor LED (BiLED) + - Various Resistors (1x 510Ω, 3x 1kΩ) +- Wire (available in classroom) + +### Project Template + +{{< link href="lab1_template.zip" content="lab1_template.zip" title="Download lab1_template.zip" download="lab1_template.zip" card=true >}} + +## Part A: Build and Test I/O + +The first day of this lab consists of building the hardware required, producing the GPIO initialization code, and implementing tests to verify the correct operation of all inputs and outputs. The circuitry needed is shown in the Figure Lab 1 Schematic. Note that this schematic provides both the circuitry included on the |rslk| and that which needs to be built. The circuitry that needs to be built should be done on an external breadboard, *not the one mounted on the RSLK*, to allow for other teams to use the same car. + +> [!WARNING] +> There are no 5V connections within Lab 1 Schematic, only 3.3V! This is because the microcontroller pins are only 3.3V tolerant and will likely fail if 5V is applied to them. Ensure that you never use 5V when connecting to this microcontroller! + +{{< image src="lab1_schematics.svg" width="480px" caption="Lab 1 Circuit Schematic" >}} + +Both the left and right drive motors on the RSLK are controlled by two output lines: **On/Off** and **Direction**. The **On/Off** line will turn the motor on (High) or off (Low) whereas the **Direction** pin indicates if the wheel should rotate forward (Low) or reverse (High). + +With the circuitry built, the GPIO pins must be initialized. **You must use the template project** [lab1_template.zip](lab1_template.zip). This template project has a purpose-built library ([Lab1Lib Driver Library](#lab1lib-driver-library-functions)) for interacting with the motors. Within this project, initialize the pins as specified in the schematic within `GPIOInit()` using the **DriverLib** functions only; do not use **registers**. + +> [!IMPORTANT] +> You must use the DriverLib function +> +> ```c +> void GPIO_setAsInputPinWithPullUpResistor(uint8_t port,uint8_t pins); +> ``` +> +> to initialize the bumper buttons. This is needed as the corresponding resistor, **R_PU**, as shown on the schematic is **part of the microcontroller** and not an actual component. Therefore, **R_PU** must be enabled through the microcontroller to create the needed **pullup resistor**. + +Finally, finish the code provided within function `testIO()` to test the inputs and outputs. The input values should be printed each time a keyboard key is pressed. Further, if the keyboard key pressed is contained within the list below, the specified operation should be completed to test the output. An example on how to complete this is given in the template code. + +| Key | Function | +|:-----------:|:-------------------------:| +| `a` | LEDFL On | +| `z` | LEDFL Off | +| `s` | LEDFR On | +| `x` | LEDFR off | +| `q` | BiLED1 Red | +| `w` | BiLED1 Off | +| `e` | BiLED1 Green | + +> [!WARNING] +> Do not forget to turn the car on to test! The motors will not work without the car being turned on; however, all other components work regardless. + +To turn on/off the car: Push the very small button marked "Power" on the back corner of the car. A blue LED will light near the car to indicate it is on, **assuming there are charged batteries in the car**. + +Please remember to turn off the car when you are done with it! + +Ask a staff member to check off **Part A** when complete; then continue with **Part B**. + +## Part B: Pattern Input and Running + +With the inputs and outputs built, configured, and tested, the pattern control routine may be added to the project. As provided in the description above, each of the bumper buttons are used to input a specific action into the pattern. They should be configured such that: + +- BMP0 adds the "turn right 90°" segment +- BMP1 adds the "turn right 45°" segment +- BMP2 adds the "drive forward" segment +- BMP3 adds the "stop for 1s" segment +- BMP4 adds the "turn left 45°" segment +- BMP5 adds the "turn left 90°" segment + +Each time a bumper button is pressed, **LEDFR** and **LEDFL** should switch off or on, with one always being on; this used to indicate a success input of a segment. If the breadboard pushbutton is pressed, the last segment input should be deleted from the program. Finally, if the breadboard slide switch is toggled from off to on, the program should trigger the pattern to be run and the BiLED lit to GREEN. Once the pattern completes, the BiLED should be lit RED until the slide switch is toggled back off. While the BiLED is lit either color, the inputs are ignored. + +The simple functional description above can be translated into a flow diagram: + +{{< image src="lab1_flow.svg" width="480px" caption=" Lab 1 Flowchart" >}} + +Blocks with red text indicate functionality provided by functions within the [Lab1Lib Driver Library](#lab1lib-driver-library-functions). + +> [!WARNING] +> The bumper buttons are prone to bouncing. You will need to debounce your button press/release and slide switch on/off detection to avoid registering multiple button presses for a single physical press. + +Implement the control scheme above within the function `controlSystem()`. The flow chart must be **explicitly followed**; that is, do not make assumptions about system behavior that are not described by the diagram. You will need to comment out the function call to `testIO()` and uncomment the call to `controlSystem()` within the `main()` function's `while(1)` loop. + +Ask a staff member to check off **Part B** when complete and submit the final code to [Gradescope]. The code must successfully implement the logic as described above and not be prone to button bouncing. For demonstrational purposes, a simplistic obstacle course may be set up in the classroom for the cars to traverse. + +## Lab1Lib Driver Library Functions + +### initSequence + +```c +void initSequence(void) +``` + +This function initializes the Lab1Lib Driver. + +### recordSegment + +```c +int8_t recordSegment(int8_t mv) +``` + +This function adds a segment to the programmed sequence. The input, `int8_t mv`, represents the segment to add: + +| `mv` value | Corresponding Segment | +|:----------:|:------------------------:| +| -2 | Drive and Turn 90° Left | +| -1 | Drive and Turn 45° Left | +| 0 | Drive Straight | +| 1 | Drive and Turn 45° Right | +| 2 | Drive and Turn 90° Right | +| 127 | Stop for 1s | + +This function will output: + +- `0` if segment was added to the sequence +- `1` if the segment has reached the maximum length (50), segment was not added +- `-1` if the value of `mv` is not in the table above + +### popSegment + +```c +uint8_t popSegment(void) +``` +This function removes the most recently added segment. Outputs 0 if a segment was erased or 1 is there is no segments to erase (sequence is empty). + +### clearSequence + +```c +void clearSequence(void) +``` + +Erase the currently programmed sequence. + +### runSequence + +```c +uint8_t runSequence(void) +``` + +Runs the programmed sequence. Returns 0 if started properly, 1 if the sequence is empty, or 2 if the GPIO pins for the motor are not set up properly. In the case of a return of 2, the program will also print a message indicating the issue. + +### statusSegment + +```c +int8_t statusSegment(void) +``` + +Returns the currently running segment in the sequence (see table for `record_segment`) or 100 if the sequence is not running (either hasn't run or is complete). + +### statusSequence + +```c +uint8_t statusSequence(void) +``` + +Returns the step that a running sequence is on (1,2,3, etc.) or 100 if the sequence is not running (either hasn't run or is complete) + +### getSequenceLength + +```c +uint8_t getSequenceLength(void) +``` + +Returns the total number of segments currently programmed into the sequence. The maximum length of a sequence is 50. + +## My Approach + +### Part A + +The Part A is not that hard, the trick is that you need use all kinds of functions to setup pins. + +For `GPIOInit()` it should looks like + +```c +void GPIOInit(){ + //MP0 ~ BMP5 P4.0, P4.2, P4.3, P4.5, P4.6, P4.7 + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN0); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN2); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN3); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN5); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN6); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN7); + + //PB1 P2.4 + //PB2 P2.5 + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN4); + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN5); + + //SS1 P5.6 + GPIO_setAsInputPin(GPIO_PORT_P5, GPIO_PIN6); + + //LEDFL P8.0 + //LEDFR P8.5 + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + + //BiColor LED P6.0, P6.1 + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN1); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + + //left and right motor + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN4); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN4); + + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5); +} +``` + +Then, just finish the rest of `TestIO()`. + +```c +void testIO(){ + while(1){ + uint8_t cmd = getchar(); + if(cmd == 'a'){ + // Turn LEDL On + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + printf("LEDL is on.\n\r"); + + }else if(cmd == 'z'){ + // Turn LEDL Off + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN0); + printf("LEDL is off.\n\r"); + + }else if(cmd == 's'){ + //Turn LEDR On + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + printf("LEDR is on.\n\r"); + + } else if (cmd == 'x'){ + //Turn LEDR Off + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN5); + printf("LEDR is off.\n\r"); + + } else if (cmd == 'q'){ + //Turn BiLED Red + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + printf("Turn BiLED Red.\n\r"); + + } else if (cmd == 'w'){ + //Turn BiLED Off + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0 | GPIO_PIN1); + printf("Turn BiLED off.\n\r"); + + } else if (cmd == 'e'){ + //Turn BiLED Green + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN1); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + printf("Turn BiLED Green.\n\r"); + } + } +} +``` + +The BMPs need to use `GPIO_setAsInputPinWithPullUpResistor()` to setup the pins, and PBs need to use `GPIO_setAsInputPin()` to setup pins. Since, we already connect resistor to PBs. + +### Part B + +Part B is way more complex. If you are looking at the given flowchart. You probably will be lost. So, I just rewrite the flowchart using mermaid. And make it into a single loop view (it will work, since there is an infinite loop inside the main program. `controlSystem()` only needs to be a single loop) + +```mermaid +flowchart TB + A([Start / Infinite Loop]) --> B{Check SS1 State} + B -- Off --> C[Turn BiLED OFF] + B -- On --> D{Has Pattern Started?} + D -- No --> E[Start Pattern] + D -- Yes --> F{Is Pattern Complete?} + F -- No --> G[Turn BiLED GREEN] + F -- Yes --> H[Turn BiLED RED] + C --> I{Any BMPx Pressed?} + I -- Yes --> J[Add Segment to Pattern] + J --> K[Toggle LEDFR/L States] + K --> L[Wait For All Buttons To Be Released] + L --> M{PB1 Pressed?} + I -- No --> M + M -- Yes --> N[Remove Last Segment] + N --> L[Wait For All Buttons To Be Released] + M -- No --> P{PB2 Pressed?} + P -- Yes --> Q[Delete Entire Pattern] + Q --> L[Wait For All Buttons To Be Released] + P -- No --> L +``` + +After that, we can create our function easier. (The complete main.c is at the bottom of page) + +```c +void controlSystem(void){ + // Keep track whether sequence is currently running (so we know + // if it just finished, or if it's not started at all yet, etc.) + static uint8_t patternRunning = 0; + static uint8_t runSeq = 1; + + uint8_t ss_state = GPIO_getInputPinValue(GPIO_PORT_P5, GPIO_PIN6); + + if (ss_state == GPIO_INPUT_PIN_HIGH){ + //in case SS1 is on + printf("SS1 is on\n\r"); + if (statusSequence() == 100){ + //in case the sequence is complete or empty + uint8_t seqLength = getSequenceLength(); + if (seqLength == 0){ + //in case sequence is empty + patternRunning = 1; + printf("sequence is empty, won't start\n\r"); + } else { + //in case sequence is not empty + uint8_t seqCallback; + if (runSeq == 1){ + seqCallback = runSequence(); + runSeq = 0; + } + if (seqCallback == 0){ + //in case sequence started OK + printf("sequence started OK\n\r"); + } else if (seqCallback == 1){ + //in case sequence is empty + printf("sequence is empty\n\r"); + } else if (seqCallback == 2){ + //in case GPIO error + printf("fail to start sequence\n\r"); + } + } + } + if (patternRunning){ + //in case sequence is running + if (statusSequence() == 100){ + //in case sequence is finished => turn BiLED RED + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + } else{ + //in case sequence is running => Turn BiLED GREEN + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + } + } + } else{ + //in case SS1 is off + patternRunning = 0; + //turn BiLED off + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1); + + // A static toggle variable to keep track of which front LED + // is on next time we successfully record a segment + static uint8_t toggleLED = 0; + + if (runSeq == 0){ + runSeq = 1; + clearSequence(); + } + + // Check each bumper individually + if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(2); // Turn right 90 + if (recStatus == 0) { + printf("Turn right 90 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + printf("Right LED toggled.\r\n"); + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) {} + _delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(1); // Turn right 45 + if (recStatus == 0) { + printf("Turn right 45 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(0); // Drive forward + if (recStatus == 0) { + printf("Drive forward added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(127); // Stop for 1 s + if (recStatus == 0) { + printf("Stop for 1 s added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(-1); // Turn left 45 + if (recStatus == 0) { + printf("Turn left 45 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(-2); // Turn left 90 + if (recStatus == 0) { + printf("Turn left 90 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + // -- Check PB1 (pop last segment) -- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW) + { + // Wait for release + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + uint8_t popRes = popSegment(); + if(popRes == 0) + { + printf("Last segment popped.\r\n"); + } + else + { + printf("No segment to pop.\r\n"); + } + } + + // -- Check PB2 (clear entire sequence) -- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) + { + // Wait for release + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + clearSequence(); + printf("Entire sequence cleared.\r\n"); + } + } +} +``` + +There are a few tricks. First, the BMPs will bounce as we released the micro switches. Without debouncing, it will create more than 50 clicks in a seconds. To debounce, I used an empty while loop to wait it to be released and a delay to wait the bouncing ends. + +```diff +if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { ++ while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} ++ __delay_cycles(240e3); + //... +} +``` + +Second, make sure `runSequence()` only run once as needed. Otherwise, the car will never stop. My solution to that is create a global variable to track that and keep it updated. + +```diff +void controlSystem(void){ ++ static uint8_t runSeq = 1; + if (ss_state == GPIO_INPUT_PIN_HIGH){ + //in case SS1 is on + if (statusSequence() == 100){ + //in case the sequence is complete or empty + if (seqLength == 0){ + //in case sequence is empty + } else { + //in case sequence is not empty ++ if (runSeq == 1){ + seqCallback = runSequence(); ++ runSeq = 0; + } + //... + } + } + //... + } else{ + //in case SS1 is off ++ if (runSeq == 0){ ++ runSeq = 1; ++ clearSequence(); ++ } + //... + } +} +``` + +Last, print enough debug information and error log based on status code which returned by the functions. + +### Final Code + +```c +#include "engr2350_msp432.h" +#include "lab1lib.h" +#include + +void GPIOInit(); +void testIO(); +void controlSystem(); + +uint8_t LEDFL = 0; // Two variables to store the state of +uint8_t LEDFR = 0; // the front left/right LEDs (on-car) + +int main() { + + sysInit(); // Basic car initialization + initSequence(); // Initializes the lab1Lib Driver + GPIOInit(); + + printf("\r\n\n" + "===========\r\n" + "Lab 1 Begin\r\n" + "===========\r\n"); + + while(1){ + //testIO(); // Used in Part A to test the IO + controlSystem(); // Used in Part B to implement the desired functionality + } +} + + +void GPIOInit(){ + //MP0 ~ BMP5 P4.0, P4.2, P4.3, P4.5, P4.6, P4.7 + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN0); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN2); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN3); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN5); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN6); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN7); + + //PB1 P2.4 + //PB2 P2.5 + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN4); + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN5); + + //SS1 P5.6 + GPIO_setAsInputPin(GPIO_PORT_P5, GPIO_PIN6); + + //LEDFL P8.0 + //LEDFR P8.5 + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + + //BiColor LED P6.0, P6.1 + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN1); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + + //left and right motor + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN4); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN4); + + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5); +} + +void testIO(){ + while(1){ + uint8_t cmd = getchar(); + if(cmd == 'a'){ + // Turn LEDL On + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + printf("LEDL is on.\n\r"); + + }else if(cmd == 'z'){ + // Turn LEDL Off + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN0); + printf("LEDL is off.\n\r"); + + }else if(cmd == 's'){ + //Turn LEDR On + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + printf("LEDR is on.\n\r"); + + } else if (cmd == 'x'){ + //Turn LEDR Off + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN5); + printf("LEDR is off.\n\r"); + + } else if (cmd == 'q'){ + //Turn BiLED Red + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + printf("Turn BiLED Red.\n\r"); + + } else if (cmd == 'w'){ + //Turn BiLED Off + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0 | GPIO_PIN1); + printf("Turn BiLED off.\n\r"); + + } else if (cmd == 'e'){ + //Turn BiLED Green + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN1); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + printf("Turn BiLED Green.\n\r"); + } + } +} + +void controlSystem(void){ + // Keep track whether sequence is currently running (so we know + // if it just finished, or if it's not started at all yet, etc.) + static uint8_t patternRunning = 0; + static uint8_t runSeq = 1; + + uint8_t ss_state = GPIO_getInputPinValue(GPIO_PORT_P5, GPIO_PIN6); + + if (ss_state == GPIO_INPUT_PIN_HIGH){ + //in case SS1 is on + printf("SS1 is on\n\r"); + if (statusSequence() == 100){ + //in case the sequence is complete or empty + uint8_t seqLength = getSequenceLength(); + if (seqLength == 0){ + //in case sequence is empty + patternRunning = 1; + printf("sequence is empty, won't start\n\r"); + } else { + //in case sequence is not empty + uint8_t seqCallback; + if (runSeq == 1){ + seqCallback = runSequence(); + runSeq = 0; + } + if (seqCallback == 0){ + //in case sequence started OK + printf("sequence started OK\n\r"); + } else if (seqCallback == 1){ + //in case sequence is empty + printf("sequence is empty\n\r"); + } else if (seqCallback == 2){ + //in case GPIO error + printf("fail to start sequence\n\r"); + } + } + } + if (patternRunning){ + //in case sequence is running + if (statusSequence() == 100){ + //in case sequence is finished => turn BiLED RED + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + } else{ + //in case sequence is running => Turn BiLED GREEN + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + } + } + } else{ + //in case SS1 is off + patternRunning = 0; + //turn BiLED off + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1); + + // A static toggle variable to keep track of which front LED + // is on next time we successfully record a segment + static uint8_t toggleLED = 0; + + if (runSeq == 0){ + runSeq = 1; + clearSequence(); + } + + // Check each bumper individually + if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(2); // Turn right 90 + if (recStatus == 0) { + printf("Turn right 90 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + printf("Right LED toggled.\r\n"); + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) {} + _delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(1); // Turn right 45 + if (recStatus == 0) { + printf("Turn right 45 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(0); // Drive forward + if (recStatus == 0) { + printf("Drive forward added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(127); // Stop for 1 s + if (recStatus == 0) { + printf("Stop for 1 s added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(-1); // Turn left 45 + if (recStatus == 0) { + printf("Turn left 45 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) { + // Debounce – wait until it’s released + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~ simple debounce delay + + // Record the requested segment + int8_t recStatus = recordSegment(-2); // Turn left 90 + if (recStatus == 0) { + printf("Turn left 90 added.\r\n"); + // Toggle the front LEDs + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + // -- Check PB1 (pop last segment) -- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW) + { + // Wait for release + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + uint8_t popRes = popSegment(); + if(popRes == 0) + { + printf("Last segment popped.\r\n"); + } + else + { + printf("No segment to pop.\r\n"); + } + } + + // -- Check PB2 (clear entire sequence) -- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) + { + // Wait for release + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + clearSequence(); + printf("Entire sequence cleared.\r\n"); + } + } +} +``` + +## Area Can be Improved + +First, there are a lot of duplicated code. For example, the debouncing logic has been applied every times there is switches been turned on. I could pack them into a function and call it over times. + +```diff ++void debouncePin(uint8_t port, uint16_t pin) { ++ while (GPIO_getInputPinValue(port, pin) == GPIO_INPUT_PIN_LOW) {} ++ __delay_cycles(240000); ++} + +if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { +- while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} +- __delay_cycles(240000); ++ debouncePin(GPIO_PORT_P4, GPIO_PIN0); + // ... do the rest ... +} +``` + +Farther, we can move more code into function For example, put "recordSegment" checks in a function. Normally, we do something like + +```c +int8_t recStatus = recordSegment(2); // or some other value +if (recStatus == 0) { + // ... +} else if (recStatus == 1) { + // ... +} else if (recStatus == -1) { + // ... +} +``` + +Because it repeats the same checks and messages, we could make a helper function. + +```c +void handleSegmentRecord(int8_t mv, uint8_t *toggleLED, const char *message) +{ + int8_t recStatus = recordSegment(mv); + if (recStatus == 0) { + printf("%s added.\r\n", message); + toggleFrontLEDs(toggleLED); + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized.\r\n"); + } +} +``` + +Then we can do: + +```c +if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { + debouncePin(GPIO_PORT_P4, GPIO_PIN0); + handleSegmentRecord(2, &toggleLED, "Turn right 90"); +} +``` diff --git a/content/en/posts/engr-2350/lab01/lab1_flow.svg b/content/en/posts/engr-2350/lab01/lab1_flow.svg new file mode 100644 index 0000000..4eb7027 --- /dev/null +++ b/content/en/posts/engr-2350/lab01/lab1_flow.svg @@ -0,0 +1,974 @@ + + + + + + + + + + + + + + + + + + + + + + + Decision + A decision or switching type operation. + + + + Auxiliary Operation + Offline operation. + + + + + + + + + Wait For All ButtonsTo Be Released + + + + Decision + A decision or switching type operation. + + + + Decision + A decision or switching type operation. + + + Decision + A decision or switching type operation. + + + Check SS1State + + + + + Add Segmentto Pattern + + + + + + + + Turn BiLED OFF + + + + + + Infinite Loop + Off + On + No + Yes + + + + + Decision + A decision or switching type operation. + + + AnyBMPxPressed? + + + + + + Toggle Statesof LEDFR/L + + + + + + PB1Pressed? + + + + + + + HasPatternStarted?† + + + IsPatternComplete? + + + + + + + Start Pattern + + + + + + + + Turn BiLED GREEN + + + Turn BiLED RED + + + + + No + Yes + + Yes + No + † Pattern is only started once per SS1 toggle ON + + + + + Remove Last Segment + + + + + + + PB2Pressed? + + + + + + + Delete EntirePattern + + + + + + + No + + Yes + + Yes + + + + + No + + + diff --git a/content/en/posts/engr-2350/lab01/lab1_schematics.svg b/content/en/posts/engr-2350/lab01/lab1_schematics.svg new file mode 100644 index 0000000..f93c23e --- /dev/null +++ b/content/en/posts/engr-2350/lab01/lab1_schematics.svg @@ -0,0 +1 @@ +510GNDR_PUBMP5GND+3.3VSS1+3.3VMicrocontrollerMSP432P401R1k1k1kPB1BiLED1LEDFL+3.3VGNDGNDR_PUBMP0LEDFRP8.0P4.7P3.7P6.1P5.4DirectionP6.0DirectionOFFP5.5P3.6P8.5P4.0ONExists on TI-RSLKLEFTMOTORBuild on ProtoboardRIGHTMOTOROn/~{Off}On/~{Off}BMPO-BMP5 are all connected inthe same fashion to pins (in order):P4.0,P4.2,P4.3,P4.5,P4.6,P4.7P5.6P3.5+3.3VBMP5R_PUGNDBMP0R_PU+3.3VGNDGND1kPB11k \ No newline at end of file diff --git a/content/en/posts/engr-2350/lab01/lab1_template.zip b/content/en/posts/engr-2350/lab01/lab1_template.zip new file mode 100644 index 0000000..f9a939a Binary files /dev/null and b/content/en/posts/engr-2350/lab01/lab1_template.zip differ diff --git a/content/zh-cn/posts/csci-1100/crib-sheets/index.md b/content/zh-cn/posts/csci-1100/crib-sheets/index.md index 1d9b1fa..d29b013 100644 --- a/content/zh-cn/posts/csci-1100/crib-sheets/index.md +++ b/content/zh-cn/posts/csci-1100/crib-sheets/index.md @@ -17,7 +17,7 @@ comment: true weight: 0 tags: - CSCI 1100 - - 作业 + - 考试 - RPI - Python - 编程 diff --git a/content/zh-cn/posts/csci-1200/hw-2/index.md b/content/zh-cn/posts/csci-1200/hw-2/index.md index 9073fcf..402e678 100644 --- a/content/zh-cn/posts/csci-1200/hw-2/index.md +++ b/content/zh-cn/posts/csci-1200/hw-2/index.md @@ -591,9 +591,9 @@ classDiagram void exportDrivers(const std::string &filename, const std::vector &drivers) { //... std::ofstream ofs(filename); - - for (const auto &d : drivers) { - + for (int i = 0; i < (int)drivers.size(); i++) { - + const Driver &d = drivers[i]; + - for (const auto &d : drivers) { + + for (int i = 0; i < (int)drivers.size(); i++) { + + const Driver &d = drivers[i]; ofs << d.toFileString() << "\n"; } ofs.close(); diff --git a/content/zh-cn/posts/engr-2350/lab01/index.md b/content/zh-cn/posts/engr-2350/lab01/index.md new file mode 100644 index 0000000..9ed3727 --- /dev/null +++ b/content/zh-cn/posts/engr-2350/lab01/index.md @@ -0,0 +1,1106 @@ +--- +title: ENGR 2350 - 实验 1 - Digital Input/Output (GPIO) +subtitle: +date: 2025-02-10T10:10:37-05:00 +lastmod: 2025-02-10T10:10:37-05:00 +slug: engr-2350-lab-01 +draft: false +author: + name: James + link: https://www.jamesflare.com + email: + avatar: /site-logo.avif +description: +keywords: +license: +comment: true +weight: 0 +tags: + - C语言 + - 编程 + - RPI + - ENGR 2350 + - Lab +categories: + - 编程语言 + - Electrical Engineering +collections: + - ENGR 2350 +hiddenFromHomePage: false +hiddenFromSearch: false +hiddenFromRss: false +hiddenFromRelated: false +summary: +resources: + - name: featured-image + src: featured-image.jpg + - name: featured-image-preview + src: featured-image-preview.jpg +toc: true +math: false +lightgallery: true +password: +message: +repost: + enable: false + url: + +# See details front matter: https://fixit.lruihao.cn/documentation/content-management/introduction/#front-matter +--- + + + +## 实验简介 + +在本实验室中,使用简单的数字输入来编程 TI-RSLK 使其按照由独立段组成的期望模式运行: + +1. 驱动并左转90° +2. 驱动并左转45° +3. 前进 +4. 驱动并右转45° +5. 驱动并右转90° +6. 停止1秒。 + +汽车上的碰撞按钮将用于输入每个连续步骤,而面包板上的滑动开关则会触发已输入的模式执行和/或停止。一个按键可用于删除最后一步输入,另一个按键则可清除所有输入步骤。双色 LED 将指示模式是否正在运行(绿色),模式是否完成(红色)或者程序是否在等待用户输入(关闭)。 + +### 实验室目标 + +本实验室旨在进一步加深学生对以下内容的理解: + +* Code Composer Studio (CCS) 集成开发环境 +* MSP432P401R 微控制器编程, +* 输入和输出的实现与使用, +* 向功能系统发展的模块化 C 程序开发,以及 +* TI 机器人系统学习套件(TI-RSLK)的功能。 + +### 准备 + +学生应在开始本实验室之前完成活动 1-5。*理解活动 5 的任务对于本实验至关重要。* + +### 硬件和工具 + +- TI-RSLK 机器人汽车 +- 面包板 +- 组件(提供): + - 2x 按键 + - 1x 滑动开关 + - 1x 双色 LED (BiLED) + - 各种电阻(1x 510Ω,3x 1kΩ) +- 导线(在教室提供) + +### 项目模板 + +{{< link href="lab1_template.zip" content="lab1_template.zip" title="下载 lab1_template.zip" download="lab1_template.zip" card=true >}} + +## 第一部分:构建和测试 I/O + +本实验室的第一天包括建立所需的硬件,生成 GPIO 初始化代码,并实现测试以验证所有输入和输出的正确操作。所需电路如图 Lab 1 原理图所示。请注意,此原理图提供了 TI-RSLK 上包含的电路以及需要在外部面包板上构建的部分电路。需要在外部面包板上构建的电路应允许其他团队使用同一辆车。 + +> [!WARNING] +> 在 Lab 1 原理图中没有5V连接!只有3.3V!这是因为微控制器引脚仅支持3.3V,如果施加5V可能会损坏。确保您在连接此微控制器时不要使用5V! + +{{< image src="lab1_schematics.svg" width="480px" caption="Lab 1 原理图" >}} + +RSLK 上的左、右驱动电机由两条输出线控制:**On/Off** 和 **Direction**。**On/Off** 线将使电机开启(高电平)或关闭(低电平),而 **Direction** 引脚表示轮子是否向前旋转(低电平)或向后旋转(高电平)。 + +在搭建好电路之后,需要初始化 GPIO 引脚。**您必须使用模板项目** [lab1_template.zip](lab1_template.zip)。此模板项目有一个专门的库([Lab1Lib 驱动程序库](#lab1lib-driver-library-functions))用于与电机交互。在此项目中,使用 **DriverLib** 函数初始化引脚,不要使用 **寄存器**。 + +> [!IMPORTANT] +> 您必须使用 DriverLib 函数 +> +> ```c +> void GPIO_setAsInputPinWithPullUpResistor(uint8_t port,uint8_t pins); +> ``` +> +> 来初始化碰撞按钮。这是必需的,因为在原理图上所示的相应电阻 **R_PU** 是微控制器的一部分,并不是一个实际组件。因此,必须通过启用微控制器上的 **R_PU** 来创建所需的 **下拉电阻**。 + +最后,在 `testIO()` 函数提供的代码中完成测试输入和输出的实现。每次按下键盘键时,应打印输入值。此外,如果按下的键盘键包含在以下列表中的某个位置,则应执行指定的操作以测试输出。模板代码提供了如何完成此操作的例子。 +| Key | Function | +|:-----------:|:-------------------------:| +| `a` | LEDFL On | +| `z` | LEDFL Off | +| `s` | LEDFR On | +| `x` | LEDFR off | +| `q` | BiLED1 Red | +| `w` | BiLED1 Off | +| `e` | BiLED1 Green | + +> [!WARNING] +> 不要忘记在测试时打开汽车!如果不开启汽车,电机将无法工作;然而,所有其他组件都可以正常工作。 + +要打开/关闭汽车:按下位于车后角标记为“Power”的非常小的按钮。如果汽车内有充满电的电池,则靠近汽车的一个蓝色 LED 会亮起以表示它已开启。 + +请记得在使用完毕时关闭汽车! + +完成第一部分后,请工作人员检查并继续进行第二部分。 + +## 第二部分:模式输入和运行 + +在构建、配置和测试了输入和输出之后,可以将模式���制程序添加到项目中。如上文描述所示,每个碰撞按钮用于向模式输入一个特定的动作。它们应被配置为: + +- BMP0 添加“右转90°”段 +- BMP1 添加“右转45°”段 +- BMP2 添加“前进”段 +- BMP3 添加“停止1秒”段 +- BMP4 添加“左转45°”段 +- BMP5 添加“左转90°”段 + +每当按下碰撞按钮时,会切换 LEDFR 或 LEDFL 的状态,并保持其中一个常亮,以表示已成功添加一个步骤。如果面包板按键被按压,则应从程序中删除最后一个输入的步骤。最后,如果面包板滑动开关从关闭状态切换到开启状态,则程序应该触发模式运行并点亮 BiLED 为绿色。一旦模式完成,BiLED 应该在滑动开关再次关闭之前保持红色亮起。当 BiLED 处于任何颜色时,输入将被忽略。 + +上面的简单功能描述可以转换成流程图: + +{{< image src="lab1_flow.svg" width="480px" caption=" Lab 1 流程图" >}} + +带有红色文本的块表示由 [Lab1Lib 驱动程序库](#lab1lib-driver-library-functions)中的函数提供的功能。 + +> [!WARNING] +> 碰撞按钮容易出现弹跳。您需要去抖您的按键按压/释放和滑动开关开/关检测,以避免单次物理按压被注册为多次按键按压。 + +在 `controlSystem()` 函数中实现上述控制方案。流程图必须**严格按照执行**;也就是说,不要对未由图表描述的行为做出假设。您需要注释掉 `main()` 函数的 `while(1)` 循环中的 `testIO()` 调用,并取消注释 `controlSystem()` 的调用。 + +完成第二部分后,请工作人员检查并提交最终代码到 [Gradescope]。该代码必须成功实现上述逻辑,且不易受到按键弹跳的影响。为了演示目的,在教室里可以设置一个简单的障碍课程供汽车通过。 + +## Lab1Lib 驱动程序库函数 + +### initSequence + +```c +void initSequence(void) +``` + +此函数初始化 Lab1Lib 驱动程序。 + +### recordSegment + +```c +int8_t recordSegment(int8_t mv) +``` + +该函数向编程序列中添加一个段。输入 `int8_t mv` 表示要添加的段: + +| `mv` 值 | 对应的段 | +|:----------:|:------------------------:| +| -2 | 驱动并左转90° | +| -1 | 驱动并左转45° | +| 0 | 直行 | +| 1 | 驱动并右转45° | +| 2 | 驱动并右转90° | +| 127 | 停止1秒 | + +该函数将输出: + +- `0` 如果段已添加到序列中 +- `1` 如果段达到最大长度(50),未添加 +- `-1` 如果 `mv` 的值不在上面的表中 + +### popSegment + +```c +uint8_t popSegment(void) +``` + +此函数删除最近添加的一个段。输出 0 表示已擦除一个段,或 1 表示没有段可擦除(序列为空)。 + +### clearSequence + +```c +void clearSequence(void) +``` + +清除当前编程的序列。 + +### runSequence + +```c +uint8_t runSequence(void) +``` + +运行编程的序列。返回值为: + +- `0` 如果启动成功, +- `1` 如果序列为空,或者 +- `2` 如果电机引脚未正确设置。 + +在返回 2 的情况下,程序还会打印一条消息以指示问题所在。 + +### statusSegment + +```c +int8_t statusSegment(void) +``` + +返回当前正在运行的段(参见 `record_segment` 表)或如果序列没有运行则返回100。 + +### statusSequence + +```c +uint8_t statusSequence(void) +``` + +返回正在运行的序列中的步骤编号(如 1,2,3 等),或者如果序列未运行,则返回100。 + +### getSequenceLength + +```c +uint8_t getSequenceLength(void) +``` + +返回当前编程到序列中的段总数。序列的最大长度为50。 + +## 我的方法 + +### 第一部分 + +第一部分并不难,关键是需要使用各种函数来设置引脚。 + +对于 `GPIOInit()` 应该看起来像这样: + +```c +void GPIOInit(){ + //MP0 ~ BMP5 P4.0, P4.2, P4.3, P4.5, P4.6, P4.7 + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN0); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN2); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN3); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN5); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN6); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN7); + + //PB1 P2.4 + //PB2 P2.5 + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN4); + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN5); + + //SS1 P5.6 + GPIO_setAsInputPin(GPIO_PORT_P5, GPIO_PIN6); + + //LEDFL P8.0 + //LEDFR P8.5 + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + + //BiColor LED P6.0, P6.1 + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN1); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + + //左、右电机 + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN4); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN4); + + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5); +} +``` + +然后,完成 `TestIO()` 的其余部分。 + +```c +void testIO(){ + while(1){ + uint8_t cmd = getchar(); + if(cmd == 'a'){ + // 打开 LEDL + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + printf("LEDL is on.\n\r"); + + }else if(cmd == 'z'){ + // 关闭 LEDL + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN0); + printf("LEDL is off.\n\r"); + + }else if(cmd == 's'){ + //打开 LEDR + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + printf("LEDR is on.\n\r"); + + } else if (cmd == 'x'){ + //关闭 LEDR + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN5); + printf("LEDR is off.\n\r"); + + } else if (cmd == 'q'){ + //将 BiLED 设置为红色 + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + printf("Turn BiLED Red.\n\r"); + + } else if (cmd == 'w'){ + //关闭 BiLED + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0 | GPIO_PIN1); + printf("Turn BiLED off.\n\r"); + + } else if (cmd == 'e'){ + //将 BiLED 设置为绿色 + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN1); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + printf("Turn BiLED Green.\n\r"); + } + } +} +``` + +BMPs 需要使用 `GPIO_setAsInputPinWithPullUpResistor()` 来设置引脚,而 PBs 则需要使用 `GPIO_setAsInputPin()` 来设置引脚。因为已经连接了电阻到 PBs。 + +### 第二部分 + +第二部分复杂得多。如果您查看给定的流程图,可能会感到困惑。因此,我重新绘制了流程图,并将其转换为单个循环视图(它会起作用,因为在主程序中有一个无限循环。`controlSystem()` 只需要是一个单循环) + +```mermaid +flowchart TB + A([Start / Infinite Loop]) --> B{Check SS1 State} + B -- Off --> C[Turn BiLED OFF] + B -- On --> D{Has Pattern Started?} + D -- No --> E[Start Pattern] + D -- Yes --> F{Is Pattern Complete?} + F -- No --> G[Turn BiLED GREEN] + F -- Yes --> H[Turn BiLED RED] + C --> I{Any BMPx Pressed?} + I -- Yes --> J[Add Segment to Pattern] + J --> K[Toggle LEDFR/L States] + K --> L[Wait For All Buttons To Be Released] + L --> M{PB1 Pressed?} + I -- No --> M + M -- Yes --> N[Remove Last Segment] + N --> L[Wait For All Buttons To Be Released] + M -- No --> P{PB2 Pressed?} + P -- Yes --> Q[Delete Entire Pattern] + Q --> L[Wait For All Buttons To Be Released] + P -- No --> L +``` + +之后,我们可以更容易地创建我们的函数。(完整的 main.c 在页面底部) + +```c +void controlSystem(void){ + // 用于跟踪序列是否当前正在运行(以便我们知道 + // 它刚刚完成,或者根本没有开始等) + static uint8_t patternRunning = 0; + static uint8_t runSeq = 1; + + uint8_t ss_state = GPIO_getInputPinValue(GPIO_PORT_P5, GPIO_PIN6); + + if (ss_state == GPIO_INPUT_PIN_HIGH){ + // 如果 SS1 打开 + printf("SS1 is on\n\r"); + if (statusSequence() == 100){ + // 如果序列完成或为空 + uint8_t seqLength = getSequenceLength(); + if (seqLength == 0){ + // 如果序列为空 + patternRunning = 1; + printf("sequence is empty, won't start\n\r"); + } else { + // 如果序列不为空 + uint8_t seqCallback; + if (runSeq == 1){ + seqCallback = runSequence(); + runSeq = 0; + } + if (seqCallback == 0){ + // 如果序列启动成功 + printf("sequence started OK\n\r"); + } else if (seqCallback == 1){ + // 如果序列为空 + printf("sequence is empty\n\r"); + } else if (seqCallback == 2){ + // 如果 GPIO 错误 + printf("fail to start sequence\n\r"); + } + } + } + if (patternRunning){ + // 如果序列正在运行 + if (statusSequence() == 100){ + // 如果序列完成 => 将 BiLED 设置为红色 + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + } else{ + // 如果序列正在运行 => 将 BiLED 设置为绿色 + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + } + } + } else{ + // 如果 SS1 关闭 + patternRunning = 0; + // 将 BiLED 设置为关闭状态 + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1); + + // 静态切换变量,用于跟踪下次成功记录段时哪个前 LED 应该亮起 + static uint8_t toggleLED = 0; + + if (runSeq == 0){ + runSeq = 1; + clearSequence(); + } + + // 单独检查每个碰撞按钮 + if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(2); // 右转90° + if (recStatus == 0) { + printf("Turn right 90 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + printf("Right LED toggled.\r\n"); + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) {} + _delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(1); // 右转45° + if (recStatus == 0) { + printf("Turn right 45 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(0); // 前进 + if (recStatus == 0) { + printf("Drive forward added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(127); // 停止1秒 + if (recStatus == 0) { + printf("Stop for 1 s added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(-1); // 左转45° + if (recStatus == 0) { + printf("Turn left 45 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(-2); // 左转90° + if (recStatus == 0) { + printf("Turn left 90 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + // -- 检查 PB1(弹出最后一步)-- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW) + { + // 等待释放 + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + uint8_t popRes = popSegment(); + if(popRes == 0) + { + printf("Last segment popped.\r\n"); + } + else + { + printf("No segment to pop.\r\n"); + } + } + + // -- 检查 PB2(清除整个序列)-- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) + { + // 等待释放 + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + clearSequence(); + printf("Entire sequence cleared.\r\n"); + } + } +} +``` + +这里有一些技巧。首先,BMPs 在释放微动开关时会弹跳。没有去抖的话,在一秒钟内会产生超过50次点击。为了去抖,我使用了一个空循环等待其被释放,并且延迟以等待弹跳结束。 + +```diff +if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { ++ while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} ++ __delay_cycles(240e3); + //... +} +``` + +其次,确保 `runSequence()` 只在需要时运行一次。否则汽车将永远无法停止。我的解决方案是创建一个全局变量来跟踪这一点并保持更新。 + +```diff +void controlSystem(void){ ++ static uint8_t runSeq = 1; + if (ss_state == GPIO_INPUT_PIN_HIGH){ + // 如果 SS1 打开 + if (statusSequence() == 100){ + // 如果序列完成或为空 + if (seqLength == 0){ + // 如果序列为空 + } else { + // 如果序列不为空 ++ if (runSeq == 1){ + seqCallback = runSequence(); ++ runSeq = 0; + } + //... + } + } + //... + } else{ + // 如果 SS1 关闭 ++ if (runSeq == 0){ ++ runSeq = 1; ++ clearSequence(); ++ } + //... + } +} +``` + +最后,根据函数返回的状态码打印足够的调试信息和错误日志。 + +### 最终代码 + +```c +#include "engr2350_msp432.h" +#include "lab1lib.h" +#include + +void GPIOInit(); +void testIO(); +void controlSystem(); + +uint8_t LEDFL = 0; // 两个变量��于存储前左/右LED(车上的)的状态 +uint8_t LEDFR = 0; + +int main() { + + sysInit(); // 基本汽车初始化 + initSequence(); // 初始化 lab1Lib 驱动程序 + GPIOInit(); + + printf("\r\n\n" + "===========\r\n" + "Lab 1 Begin\r\n" + "===========\r\n"); + + while(1){ + //testIO(); // 在第一部分中用于测试 I/O + controlSystem(); // 在第二部分中实现所需的功能 + } +} + +void GPIOInit(){ + //MP0 ~ BMP5 P4.0, P4.2, P4.3, P4.5, P4.6, P4.7 + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN0); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN2); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN3); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN5); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN6); + GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P4, GPIO_PIN7); + + //PB1 P2.4 + //PB2 P2.5 + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN4); + GPIO_setAsInputPin(GPIO_PORT_P2, GPIO_PIN5); + + //SS1 P5.6 + GPIO_setAsInputPin(GPIO_PORT_P5, GPIO_PIN6); + + //LEDFL P8.0 + //LEDFR P8.5 + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + + //BiColor LED P6.0, P6.1 + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + + GPIO_setAsOutputPin(GPIO_PORT_P6, GPIO_PIN1); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + + //左、右电机 + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN7); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN4); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN4); + + GPIO_setAsOutputPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setOutputLowOnPin(GPIO_PORT_P3, GPIO_PIN6); + GPIO_setAsOutputPin(GPIO_PORT_P5, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5); +} + +void testIO(){ + while(1){ + uint8_t cmd = getchar(); + if(cmd == 'a'){ + // 打开 LEDL + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + printf("LEDL is on.\n\r"); + + }else if(cmd == 'z'){ + // 关闭 LEDL + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN0); + printf("LEDL is off.\n\r"); + + }else if(cmd == 's'){ + //打开 LEDR + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + printf("LEDR is on.\n\r"); + + } else if (cmd == 'x'){ + //关闭 LEDR + GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN5); + printf("LEDR is off.\n\r"); + + } else if (cmd == 'q'){ + //将 BiLED 设置为红色 + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + printf("Turn BiLED Red.\n\r"); + + } else if (cmd == 'w'){ + //关闭 BiLED + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN0 | GPIO_PIN1); + printf("Turn BiLED off.\n\r"); + + } else if (cmd == 'e'){ + //将 BiLED 设置为绿色 + GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN1); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + printf("Turn BiLED Green.\n\r"); + } + } +} + +void controlSystem(void){ + // 用于跟踪序列是否当前正在运行(以便我们知道 + // 如果刚刚完成,或者根本没有开始等) + static uint8_t patternRunning = 0; + static uint8_t runSeq = 1; + + uint8_t ss_state = GPIO_getInputPinValue(GPIO_PORT_P5, GPIO_PIN6); + + if (ss_state == GPIO_INPUT_PIN_HIGH){ + // 如果 SS1 打开 + printf("SS1 is on\n\r"); + if (statusSequence() == 100){ + // 如果序列完成或为空 + uint8_t seqLength = getSequenceLength(); + if (seqLength == 0){ + // 如果序列为空 + patternRunning = 1; + printf("sequence is empty, won't start\n\r"); + } else { + // 如果序列不为空 + uint8_t seqCallback; + if (runSeq == 1){ + seqCallback = runSequence(); + runSeq = 0; + } + if (seqCallback == 0){ + // 如果序列启动成功 + printf("sequence started OK\n\r"); + } else if (seqCallback == 1){ + // 如果序列为空 + printf("sequence is empty\n\r"); + } else if (seqCallback == 2){ + // 如果 GPIO 错误 + printf("fail to start sequence\n\r"); + } + } + } + if (patternRunning){ + // 如果序列正在运行 + if (statusSequence() == 100){ + // 如果序列完成 => 将 BiLED 设置为红色 + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN1); + } else{ + // 如果序列正在运行 => 将 BiLED 设置为绿色 + GPIO_setOutputHighOnPin(GPIO_PORT_P6, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN1); + } + } + } else{ + // 如果 SS1 关闭 + patternRunning = 0; + // 将 BiLED 设置为关闭状态 + GPIO_setOutputLowOnPin(GPIO_PORT_P6, GPIO_PIN0 | GPIO_PIN1); + + // 静态切换变量,用于跟踪下次成功记录段时哪个前 LED 应该亮起 + static uint8_t toggleLED = 0; + + if (runSeq == 0){ + runSeq = 1; + clearSequence(); + } + + // 单独检查每个碰撞按钮 + if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(2); // 右转90° + if (recStatus == 0) { + printf("Turn right 90 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + printf("Right LED toggled.\r\n"); + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2) == GPIO_INPUT_PIN_LOW) {} + _delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(1); // 右转45° + if (recStatus == 0) { + printf("Turn right 45 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN3) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(0); // 前进 + if (recStatus == 0) { + printf("Drive forward added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(127); // 停止1秒 + if (recStatus == 0) { + printf("Stop for 1 s added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN6) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(-1); // 左转45° + if (recStatus == 0) { + printf("Turn left 45 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + else if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) { + // 等待释放 + while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN7) == GPIO_INPUT_PIN_LOW) {} + __delay_cycles(240e3); // ~简单去抖延迟 + + // 记录请求的段 + int8_t recStatus = recordSegment(-2); // 左转90° + if (recStatus == 0) { + printf("Turn left 90 added.\r\n"); + // 切换前 LED 状态 + if (toggleLED == 0) { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN5); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN0); + toggleLED = 1; + printf("Left LED toggled.\r\n"); + } else { + GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN0); + GPIO_setOutputLowOnPin(GPIO_PORT_P8, GPIO_PIN5); + toggleLED = 0; + } + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length (50). Segment not added.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized by recordSegment.\r\n"); + } + } + // -- 检查 PB1(弹出最后一步��-- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW) + { + // 等待释放 + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN4) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + uint8_t popRes = popSegment(); + if(popRes == 0) + { + printf("Last segment popped.\r\n"); + } + else + { + printf("No segment to pop.\r\n"); + } + } + + // -- 检查 PB2(清除整个序列)-- + if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW) + { + // 等待释放 + while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5) == GPIO_INPUT_PIN_LOW){} + __delay_cycles(200000); + + clearSequence(); + printf("Entire sequence cleared.\r\n"); + } + } +} +``` + +## 可改进的部分 + +首先,有很多重复代码。例如,每次有开关被按下时都会应用去抖逻辑。我可以将它们打包成一个函数并多次调用。 + +```diff ++void debouncePin(uint8_t port, uint16_t pin) { ++ while (GPIO_getInputPinValue(port, pin) == GPIO_INPUT_PIN_LOW) {} ++ __delay_cycles(240000); ++} + +if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { +- while (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) {} +- __delay_cycles(240e3); ++ debouncePin(GPIO_PORT_P4, GPIO_PIN0); + // ... do the rest ... +} +``` + +此外,我们可以将更多代码移入函数。例如,“记录段”检查可以放入一个函数中。 + +```c +int8_t recStatus = recordSegment(2); // 或其他值 +if (recStatus == 0) { + // ... +} else if (recStatus == 1) { + // ... +} else if (recStatus == -1) { + // ... +} +``` + +因为这些检查和消息重复出现,我们可以创建一个辅助函数。 + +```c +void handleSegmentRecord(int8_t mv, uint8_t *toggleLED, const char *message) +{ + int8_t recStatus = recordSegment(mv); + if (recStatus == 0) { + printf("%s added.\r\n", message); + toggleFrontLEDs(toggleLED); + } else if (recStatus == 1) { + printf("ERROR: Sequence reached max length.\r\n"); + } else if (recStatus == -1) { + printf("ERROR: mv value not recognized.\r\n"); + } +} +``` + +然后我们可以这样写: + +```c +if (GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN0) == GPIO_INPUT_PIN_LOW) { + debouncePin(GPIO_PORT_P4, GPIO_PIN0); + handleSegmentRecord(2, &toggleLED, "Turn right 90"); +} +``` diff --git a/content/zh-cn/posts/engr-2350/lab01/lab1_flow.svg b/content/zh-cn/posts/engr-2350/lab01/lab1_flow.svg new file mode 100644 index 0000000..4eb7027 --- /dev/null +++ b/content/zh-cn/posts/engr-2350/lab01/lab1_flow.svg @@ -0,0 +1,974 @@ + + + + + + + + + + + + + + + + + + + + + + + Decision + A decision or switching type operation. + + + + Auxiliary Operation + Offline operation. + + + + + + + + + Wait For All ButtonsTo Be Released + + + + Decision + A decision or switching type operation. + + + + Decision + A decision or switching type operation. + + + Decision + A decision or switching type operation. + + + Check SS1State + + + + + Add Segmentto Pattern + + + + + + + + Turn BiLED OFF + + + + + + Infinite Loop + Off + On + No + Yes + + + + + Decision + A decision or switching type operation. + + + AnyBMPxPressed? + + + + + + Toggle Statesof LEDFR/L + + + + + + PB1Pressed? + + + + + + + HasPatternStarted?† + + + IsPatternComplete? + + + + + + + Start Pattern + + + + + + + + Turn BiLED GREEN + + + Turn BiLED RED + + + + + No + Yes + + Yes + No + † Pattern is only started once per SS1 toggle ON + + + + + Remove Last Segment + + + + + + + PB2Pressed? + + + + + + + Delete EntirePattern + + + + + + + No + + Yes + + Yes + + + + + No + + + diff --git a/content/zh-cn/posts/engr-2350/lab01/lab1_schematics.svg b/content/zh-cn/posts/engr-2350/lab01/lab1_schematics.svg new file mode 100644 index 0000000..f93c23e --- /dev/null +++ b/content/zh-cn/posts/engr-2350/lab01/lab1_schematics.svg @@ -0,0 +1 @@ +510GNDR_PUBMP5GND+3.3VSS1+3.3VMicrocontrollerMSP432P401R1k1k1kPB1BiLED1LEDFL+3.3VGNDGNDR_PUBMP0LEDFRP8.0P4.7P3.7P6.1P5.4DirectionP6.0DirectionOFFP5.5P3.6P8.5P4.0ONExists on TI-RSLKLEFTMOTORBuild on ProtoboardRIGHTMOTOROn/~{Off}On/~{Off}BMPO-BMP5 are all connected inthe same fashion to pins (in order):P4.0,P4.2,P4.3,P4.5,P4.6,P4.7P5.6P3.5+3.3VBMP5R_PUGNDBMP0R_PU+3.3VGNDGND1kPB11k \ No newline at end of file diff --git a/content/zh-cn/posts/engr-2350/lab01/lab1_template.zip b/content/zh-cn/posts/engr-2350/lab01/lab1_template.zip new file mode 100644 index 0000000..f9a939a Binary files /dev/null and b/content/zh-cn/posts/engr-2350/lab01/lab1_template.zip differ