[经验] 【转载】Multi-Touch with CapTIvate

maylove   2016-9-14 15:45 楼主
1.png
Use CapTIvate technology for multi-touch with 64 pads!

这个项目中使用的东西THINGS USED IN THIS PROJECTHardware components:
2.png
Texas Instruments MSP430 Microcontroller
×
1
Texas Instruments CapTIvate MCU Development Kit
×
1
Software apps and online services:
TI LaunchPad Energia
Texas Instruments Code Composer Studio
[tr][/tr]
Texas Instruments CapTIvate Design Center GUI查看详情

STORY
This project uses the CapTIvate MCU Development Kit as a BoosterPack and displays the pads on the Kentec 3.5" SPI screen.
The idea is to design a generic capacitive board I could use with different projects, like a board with 8 x 8 pads for a calculator.
This project shows an example of a programmable sensor.
Step 0: Hardware and Software
Hardware includes (external links)
  • and optionally a custom capacitive board.

1.png





回复评论 (3)

Software is available on Windows, Linux and macOS (external links)
3.png
Step 1: Prepare the Hardware
To turn the board with the MSP430FR2633 MCU into a BoosterPack, we are going to use the holes the board provisions for the extended 40-pin BoosterPack.
However, the MSP430FR2633 board only uses 20 pins, so we solder those 20 pins only.


4.png
The CapTIvate board rises an interrupt on pin 8 and sends the messages in bulk, through either the UART port (pins 3 and 4) or the I2C port (pins 9 and 10).
This project uses the I2C port, so we remove the jumpers for UART, TXD/P1.4and RXD/P1.5.
This frees the UART port on the LaunchPad (pins 3 and 4) for the serial console.
1.jpg
Step 2: Configure the BoosterPack
We're going to use CapTIvate Design Center GUI, available for Windows, Linux and macOS, to
  • Design the capacitive board
  • Configure the MSP430FR2633
  • Generate the code
Configuring a capacitive board is very easy thanks to the automatic options, one for assigning the I/O and another for generating the code.
11.png
Let's work with CapTIvate Design Center GUI:
  • Open the CapTIvate Design Center GUI
  • Call the menu File > Project New to create a new project, name it,
  • Drag and drop a controller and a button group from the tool bar to the working space
  • Double click on the button group to open the Button Sensor Properties window
  • Set Element group to 64
  • Close the Button Sensor Properties window
  • 01.png
  • Double click on the controller to open the Controller Properties window,
    • Select MSP430FR2633 IRHB as Device
    • Click on Auto-Assign or assign the Unconnected electrodes to the Sensors BTN00 manually
    • Check the OK label is green
    • Click on Generate Code Source
    • Close the Controller Properties window
    • Call the menu File > Project Save to save the project

    [url=] 02.png [/url]







    [url=]Referring to the schematics helps and improves the assignation of the elements to the TX and RX ports. [/url]
    [url=] 04.png [/url]
    [url=]
    Let's work with Code Composer Studio:
    • Open Code Composer Studio
    • Call the menu Project > Import CCS Project and select the project generated previously
    • Click on the hammer icon or call the menu Project > Build Project to build the project 10.png
    [/url]






点赞  2016-9-14 15:53
  • Prepare the hardware by assembling the different boards together, from left to right:
  • the capacitive board
  • the CapTIvate BoosterPack
  • the programmer board
  • Then connect the programmer board to the USB port of the computer 1.jpg Back to Code Composer Studio,
    • Click on the bug icon or call the menu Run > Debug to upload the program to the MSP430FR2633 and launch the debugger.
    • Click on the red square to end the session
    • 01.png
    • To check every works fine,
      • Return to CapTIvate Design Center GUI
      • Call the menu Communication > Connect
      • Move one finger on the capacitive board
      The screen shows the pads with proximity in orange and the pads with touch in green.
    • 1.png
    • Step 3: Program the LaunchPad
      I'm using the MSP432 LaunchPad using Energia 1.6.10E18. Energia is based on the Arduino / Wiring framework.
      The project calls three libraries:
      • the Wire library for the I2C protocol to communicate with the CapTIvate BoossterPack,
      • the SPI library for the SPI protocol to communicate with the Kentec screen BoosterPack,
      • the Screen_K35_SPI library  for the Kentec 3.5" SPI screen is bundled with Energia.
      3.1 Data Acquisition
      One single function getCapTIvate64() acquires and processes the data from the BoosterPack.
      The function isSomething() returns true if there is at least one pad with proximity or touch.
      There are five kinds of messages called packets but our project only uses the Cycle Packet, which eases reading and decoding.Remember, the capacitive board has been configured with 1 sensor, 16 cycles of 4 elements each, for a grand total of 64 pads.
    • 2.png
    • A message includes
      • one preliminary byte with the length of the message,
      • byte 0 is the Command Byte, always 0 for Cycle Packet,
      • byte 1 is the Sensor ID Byte, always 0 in the project,
      • byte 2 is the Cycle ID Byte, 0~15 in the project,
      • bytes 3 to 5 are the Cycle State Bytes with, the first 12 bits (MSB) for proximity and the last 12 bits (LSB) for touch, one bit per element of the cycle.
      • the remaining bytes of the message (except the last 2) are the Element LTA and Element Count Bytes, 4 bytes by element and 4 elements, with details (long term average and count) for each element of the cycle,
      • the last two bytes of the message for the 16-bit checksum (CRC).
      Texas Instruments provides all the information needed with the Technology Guide. 04.png
    • A logic analyser was very helpful for decoding the I2C messages! pan>
    • 5.png
    • 3.2 Screen Management
      The two functions prepareScreen() and refreshScreen() manage the screen. To speed up display, only modified areas are updated.
      The screen is refreshed only
      • after the 16 cycles have been completed, and
      • if there are pads with proximity and pads with touch.
      The screen shows the pads with proximity in orange and the pads with touch in green.
    • 7.png
      Step 4: Build and Run the Program
      Let's work with Energia!
      • Open Energia,
      • Call the menu File > Open and select the sketch CapTIvate_64.ino,
      • Click on the check icon or call the menu Sketch > Verify/Compile to compile the sketch, 9.png
      • Prepare the hardware by assembling the different boards together, from bottom to top:
        • the CapTIvate BoosterPack connected to the capacitive board,
        • the MSP432 LaunchPad,
        • the Kentec 3.5" SPI screen.
        • Then connect the MSP432 LaunchPad to the USB port of the computer.
        • 2.jpg
        • Back to Energia,
          • Click on the arrow icon or call the menu Project > Upload to upload the binary to the MSP432 LaunchPad.
          • Move one finger on the capacitive board.
          Multiple areas are displayed on the screen as CapTIvate tracks multi-touch.
          The screen shows the pads with proximity in orange and the pads with touch in green.
          Optionally, you can use Code Composer Studio instead of Energia.
          • Open Code Composer Studio,
          • Call the menu Project > Import Energia Project and select the sketch CapTIvate_64.ino,
          • Proceed as previously, build and upload.
          • 3.jpg
          • On the picture below, I put my left hand on the capacitive board: the board detected 8 pads with touch and 7 pads with proximity. 5.jpg




点赞  2016-9-14 15:59
Conclusion
The CapTIvate is very efficient in sorting signal from noise, and touch from proximity.
1.jpg
CODE
  1. ///
  2. /// @file              CapTIvate_public.ino
  3. /// [url=home.php?mod=space&uid=159083]@brief[/url]      Main sketch
  4. ///
  5. /// @details    CapTIvate project for Hackster.io
  6. /// @n [url=home.php?mod=space&uid=40190]@a[/url]       Developed with [embedXcode+](http://embedXcode.weebly.com)
  7. ///
  8. /// @author     Rei Vilo
  9. /// @author     http://www.embeddedcomputing.weebly.com
  10. /// [url=home.php?mod=space&uid=311857]@date[/url]       Jul 17, 2016
  11. /// [url=home.php?mod=space&uid=252314]@version[/url]    101
  12. ///
  13. /// @copyright        (c) Rei Vilo, 2016
  14. /// @copyright        CC = BY SA NC
  15. ///
  16. /// @see                    ReadMe.txt for references
  17. /// @n
  18. ///


  19. // Core library for code-sense - IDE-based
  20. #include "Energia.h"

  21. // Set parameters
  22. #define I2C_SLAVE 0x0a
  23. #define pinIRQ 8
  24. #define pinSingleTouch 11
  25. #define pinMultipleTouch 12

  26. // Include application, user and local libraries
  27. #include "Wire.h"
  28. #include "SPI.h"
  29. #include "Screen_K35_SPI.h"
  30. Screen_K35_SPI myScreen;

  31. // Define structures and classes
  32. struct element_t
  33. {
  34.   uint16_t LTAValue;                                                          // long term average
  35.   uint16_t countValue;
  36. };

  37. struct packetCycle_t
  38. {
  39.   uint8_t byteCommand;
  40.   uint8_t byteSensorID;
  41.   uint8_t byteCycleID;
  42.   uint16_t bitsCycleTouchState;
  43.   uint16_t bitsCycleProximityState;
  44.   uint32_t bitsCycleState;
  45.   uint8_t numberElements;
  46.   element_t element[12];
  47.   uint16_t packetChecksum;
  48. };

  49. enum state_t
  50. {
  51.   stateNone,
  52.   stateProximity,
  53.   stateTouch
  54. };

  55. // Define variables and constants
  56. uint8_t buffer[54];
  57. packetCycle_t packetCycle;
  58. uint8_t numberBytes;
  59. state_t table[8][8] = { stateNone };
  60. state_t oldTable[8][8] = { stateNone };
  61. uint8_t x, y;
  62. uint8_t countTouch = 0;
  63. uint8_t countProximity = 0;
  64. String text;

  65. // Prototypes
  66. bool isSomething();
  67. void getCapTIvate64();
  68. void prepareScreen();
  69. void refreshScreen();

  70. // Functions
  71. bool isSomething()
  72. {
  73.   return (countProximity + countTouch > 0);
  74. }

  75. void getCapTIvate64()
  76. {
  77.   uint16_t calculatedChecksum = 0;
  78.   bool flagComplete = false;
  79.   uint16_t cycles = 0;

  80.   // Initialise scan
  81.   memset(table, stateNone, sizeof(table));
  82.   countTouch = 0;
  83.   countProximity = 0;

  84.   // Perform scan
  85.   while (!flagComplete)
  86.   {
  87.     if (digitalRead(pinIRQ))
  88.     {
  89.       packetCycle.numberElements = (numberBytes - 8) / 4;

  90.       Wire.requestFrom(I2C_SLAVE, 48);
  91.       numberBytes = Wire.read();

  92.       calculatedChecksum = 0;
  93.       for (uint8_t i = 0; i < numberBytes; i++)
  94.       {
  95.         buffer[i] = Wire.read();
  96.         if (i < numberBytes - 2)
  97.         {
  98.           calculatedChecksum += buffer[i];
  99.         }
  100.       }

  101.       // Scan cycles management
  102.       packetCycle.byteCycleID = buffer[2];
  103.       bitSet(cycles, packetCycle.byteCycleID);
  104.       flagComplete = (cycles == 0xffff);

  105.       packetCycle.packetChecksum = buffer[numberBytes - 2] + buffer[numberBytes - 1] * 256;
  106.       if (calculatedChecksum == packetCycle.packetChecksum)               // Is checksum correct?
  107.       {
  108.         // Command byte
  109.         packetCycle.byteCommand = buffer[0];
  110.         // Is packet and is there some proximity or touch state?
  111.         if ((packetCycle.byteCommand == 0x01) and (buffer[3] or buffer[4] or buffer[5]))
  112.         {
  113.           packetCycle.numberElements = (numberBytes - 8) / 4;         // 4 bytes per element
  114.           packetCycle.byteSensorID = buffer[1];
  115.           packetCycle.byteCycleID = buffer[2];

  116.           packetCycle.bitsCycleState = (uint32_t)((buffer[5] << 16) + (buffer[4] << 8) + buffer[3]);

  117.           for (uint8_t elementID = 0; elementID < packetCycle.numberElements; elementID++)
  118.           {
  119.             x = 2 * elementID + (packetCycle.byteCycleID % 2);
  120.             y = packetCycle.byteCycleID / 2;

  121.             if (bitRead(packetCycle.bitsCycleState, (elementID)))
  122.             {
  123.               if (table[x][y] != stateTouch)
  124.               {
  125.                 table[x][y] = stateProximity;
  126.                 countProximity += 1;
  127.               }
  128.             }
  129.             if (bitRead(packetCycle.bitsCycleState, (12 + elementID)))
  130.             {
  131.               table[x][y] = stateTouch;
  132.               countTouch += 1;
  133.             }
  134.           }
  135.         }
  136.       }
  137.     }
  138.   }
  139. }

  140. void prepareScreen()
  141. {
  142.   myScreen.begin();
  143.   myScreen.setOrientation(0);
  144.   myScreen.setFontSize(0);
  145.   myScreen.gText(0, myScreen.screenSizeY() - 2 * myScreen.fontSizeY(), "MSP432 LP and CapTIvate BP");
  146.   myScreen.gText(0, myScreen.screenSizeY() - myScreen.fontSizeY(), "LCD_screen with Energia");

  147.   myScreen.setOrientation(1);

  148.   myScreen.setPenSolid(false);
  149.   for (uint8_t j = 0; j < 8; j++)
  150.   {
  151.     for (uint8_t i = 0; i < 8; i++)
  152.     {
  153.       myScreen.dRectangle(30 * i, 30 * j, 28, 28, whiteColour);
  154.       text = String(j * 8 + i + 1);
  155.       myScreen.gText(30 * i + 4 + (20 - myScreen.fontSizeX() * text.length()) / 2, 30 * j + 4 + (20 - myScreen.fontSizeY()) / 2, text, whiteColour);
  156.     }
  157.   }
  158.   myScreen.setPenSolid(true);
  159.   myScreen.setFontSolid(false);
  160. }

  161. void refreshScreen()
  162. {
  163.   uint16_t colourRectangle = blackColour;
  164.   uint16_t colourText = whiteColour;

  165.   for (uint8_t j = 0; j < 8; j++)
  166.   {
  167.     for (uint8_t i = 0; i < 8; i++)
  168.     {
  169.       if (table[i][j] != oldTable[i][j])
  170.       {
  171.         text = String(j * 8 + i + 1);
  172.         switch (table[i][j])
  173.         {
  174.           case stateProximity:

  175.             colourRectangle = orangeColour;
  176.             colourText = blackColour;
  177.             break;

  178.           case stateTouch:

  179.             colourRectangle = greenColour;
  180.             colourText = blackColour;
  181.             break;

  182.           default:

  183.             colourRectangle = blackColour;
  184.             colourText = whiteColour;
  185.             break;
  186.         }
  187.         myScreen.dRectangle(30 * i + 4, 30 * j + 4, 20, 20, colourRectangle);
  188.         myScreen.gText(30 * i + 4 + (20 - myScreen.fontSizeX() * text.length()) / 2, 30 * j + 4 + (20 - myScreen.fontSizeY()) / 2, text, colourText);
  189.       }
  190.     }
  191.   }
  192.   memcpy(oldTable, table, sizeof(table));
  193. }

  194. // Add setup code
  195. void setup()
  196. {
  197.   Wire.begin();

  198.   pinMode(pinIRQ, INPUT);
  199.   pinMode(RED_LED, OUTPUT);
  200.   pinMode(pinSingleTouch, INPUT); // Single touch
  201.   pinMode(pinMultipleTouch, INPUT); // Multiple touch

  202.   prepareScreen();
  203. }

  204. // Add loop code
  205. void loop()
  206. {
  207.   getCapTIvate64();
  208.   refreshScreen();
  209. }


点赞  2016-9-14 16:02
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复