Practical use of the USB interface in PIC controllers. We create the simplest usb device for communicating with our program Programming work with usb

The USB (Universal Serial Bus) bus appeared on January 15, 1996, with the approval of the first version of the standard by companies - Intel, DEC, IBM, NEC, Northen Telecom and Compaq.

The main goal of the standard set for its developers is to create the ability for users to work in Plug & Play mode with peripheral devices. This means that there should be provision for connecting the device to a running computer, automatically recognizing it immediately after connecting and then installing the appropriate drivers. In addition, it is desirable to supply power to low-power devices from the bus itself. The bus speed should be sufficient for the vast majority of peripherals. The USB controller should occupy only one interrupt regardless of the number of devices connected to the bus, that is, to solve the problem of lack of resources on the internal buses of an IBM PC of a compatible computer.

Almost all of the tasks were solved in the USB standard and in the spring of 1997 computers equipped with connectors for connecting USB devices began to appear. Now USB has become so actively implemented by manufacturers of computer peripherals that, for example, Apple Computers iMAC only has USB as an external bus.

The USB 1.0 features are as follows:

1.high speed of data exchange (full-speed) - 12 Mb it/from;

2. the maximum cable length for a high exchange rate is 5 meters;

3.low data exchange rate (low-speed) - 1.5 Mb it/from;

4. the maximum cable length for a low exchange rate is 3 meters;

5. maximum number of connected devices - 127;

6. Possible simultaneous connection of devices with different exchange rates;

8. Maximum current consumption per device - 500 mA.

Therefore, it is advisable to connect almost any peripheral device to USB 1.0 except digital camcorders and high-speed hard drives. This interface is especially convenient for connecting frequently connected / disconnected devices such as digital cameras.
The ability to use only two baud rates limits the bus usability, but significantly reduces the number of interface lines and simplifies the hardware implementation.
Direct power supply from USB is only possible for low power devices such as keyboards, mice, joysticks, etc.

USB signals are transmitted over a 4-wire cable, schematically shown in the figure below:

Figure 2.6.1 - USB signal wires

Here GND is a common wire circuit for powering peripheral devices, Vbus - +5 V also for power circuits. The D + bus is for transmitting data on the bus, and the D- bus for receiving data.
The cable to support full-speed bus is twisted pair, shielded and can also be used for low-speed operation. The cable for operation only at the minimum speed (for example, for connecting a mouse) can be any cable and can be unshielded.
The connectors used for connecting peripheral devices are divided into series: “A” series connectors (plug and socket) are only for connection to a source such as a computer, “B” series connectors (plug and socket) are only for connection to a peripheral device.

USB connectors have the following pin numbering shown in Table 2.6.1.

Table 2.6.1 - Purpose and marking of USB contacts

In 1999, the same consortium of computer companies that initiated the development of the first version of the standard for the USB bus began to actively develop version 2.0 of USB, which is distinguished by the introduction of an additional high-speed (Hi-speed) mode. The bus bandwidth has been increased 40 times, up to 480 Mbps, which made it possible to transfer video data via USB.
All previously released peripherals and high-speed cables are fully compatible. The 2.0 standard controller is already integrated into the system logic set of programmable devices (for example, the motherboard of a personal computer).

In 2008, Intel, Microsoft, Hewlett-Packard, Texas Instruments, NEC and NXP Semiconductors created the USB 3.0 standard specification. In the USB 3.0 specification, the connectors and cables of the updated standard are physically and functionally compatible with USB 2.0, but in addition to the four communication lines, four more are added. However, the new contacts in USB 3.0 connectors are located separately from the old ones on a different contact row. The USB 3.0 specification raises the maximum data transfer rate to 5 Gbps - orders of magnitude more than the 480 Mbps that USB 2.0 can provide. In addition, the maximum current strength has been increased from 500 mA to 900 mA per device, which makes it possible to power some devices that previously required a separate power supply.

Suppose you have developed a USB device that you want to work with a computer. This can be achieved in at least two ways:

1. development of a full-featured operating system driver;

2. using a special class of USB interface - devices called HID (Human Interface Device) devices.

The first method is universal: having sufficient knowledge in the field of writing drivers, you can program to work with any device at any speed supported by USB. But this is not an easy task.

The second way is as follows. There is an interface supported by modern operating systems for computer-human interaction devices or HID devices, such as:

1. keyboards, mice, joysticks;

2. various sensors and readers;

3. game steering and pedals;

4. buttons, switches, regulators.

Any such device, if it meets the requirements for HID devices, will be automatically recognized by the system and does not require writing special drivers. In addition, programming them is usually much easier than writing a specialized device driver. Unfortunately, the method has a significant drawback: the speed of information exchange with the HID device is very limited and is a maximum of 64 kB / s.

Basically, on the basis of HID technology, it is possible to organize interaction with any device, even if it is not, in the strict sense, a human-computer interface device. This eliminates the time-consuming development of a unique device driver and saves time on developing a new USB device. On the host side, communication with the device will be controlled by the standard HID driver included with the operating system. You just need to fulfill the minimum requirements of the USB-HID protocol on the device side.

It is worth noting that many USB devices that at first glance do not fall under the definition of human interaction devices, it is more logical to implement them as HID devices. This phenomenon is common in the field of manufacturing equipment, which has recently experienced massive adoption of USB technology. For example, consider a laboratory power supply with the ability to set the parameters of its output signals from a computer using a USB interface. The power source itself is undoubtedly not a means of human interaction. However, in this case, the functions implemented via the USB connection duplicate the keyboard, controls and indicators installed on the device itself. And these controls just fall under the definition of HID. Accordingly, a power supply unit with these USB functions is most logical to organize as an HID device.

In the considered example, a low data transfer rate will be sufficient for normal operation, while in other cases the devices can be very demanding on the exchange rate. Low transmission speed is the main limitation of the HID design of the device, which, in comparison with 12 Mbit / s full speed of USB 1.0 bus, looks like a big disadvantage of HID technology when it comes to choosing a specific USB implementation. However, for many communication tasks, this speed is quite enough and the HID architecture as a specialized tool takes a worthy place among the methods of organizing data exchange.

HID devices are of two types: participating (bootable) and non-participating in the initial computer boot. The most striking example of a bootable USB-HID device is a keyboard, which starts working when the computer starts up.

When developing an HID device, the following requirements imposed by the specification must be met:

1.Full speed HID device can transmit 64000 bytes every second or 64 bytes every 1ms; a low speed HID device has the ability to transmit up to 800 bytes per second or 8 bytes every 10 ms.

2. The HID device can assign its polling frequency to determine if it has fresh data to transmit.

3. The exchange of data with the HID device is carried out through a special structure called a report (Report). Each specific report can contain up to 65535 bytes of data. The structure of the report has a very flexible organization that allows you to describe any format of data transmission. In order for a specific report format to become known to the host, the microcontroller must contain a special description - a report descriptor.

USB communication is implemented directly on the microcontroller in several ways:

1.Using a controller with hardware support, for example AT90USB *, made by atmega;

2.Using software emulation of the usb interface on any microcontroller.

For software implementation, there are currently a number of ready-made solutions for various families of microcontrollers. For AVR microcontrollers, for example, Atmega8, it is possible to use the following free C libraries:

Both are fairly easy to use, provide full emulation of USB 1.1 low-speed devices with the exception of communication and electrical error handling, and run on virtually all AVR controllers with a minimum of 2KB flash, 128 bytes of RAM, and a frequency of 12 to 20 MHz.

To write applications that support Windows USB HID devices, you need the hid * header files that are included with the Windows Driver Kit (WDK), or you can use the free hidlibrary or similar.

Thus, in the general case, programming USB is a rather difficult task that requires a special microcontroller with hardware support and writing an operating system driver. However, in practice, when developing devices, it is possible to use a much simpler interface of HID devices, which is supported at the level of a standard system driver, and programming is simplified using existing function libraries.

Control questions

  1. What is the difference between D- and GND wires in USB? Why can't you use one common wire for power and signal?
  2. How many USB speed modes are there today (including version 3.0)?
  3. What is a HID device? Why is it not required to write drivers for their work in modern OS?
  4. Is it possible to implement USB devices with a microprocessor that does not have built-in interface support?
  5. What are the main differences between USB 3.0 and previous versions?

USB programming

Programming the device for tuning satellite antennas SF-50 via the USB port differs from programming via the RS-232 port only in the method of transferring data from the device to the computer and from the computer to the device. When programming via USB, a portable USB storage device (flash drive) is used. This is convenient when, for example, your computer or, more often, a laptop (netbook) does not have a serial RS-232 port on its chassis.
To program the device using a USB stick you will need:
- USB storage device (flash drive) formatted in the FAT-32 file system;
- AliEditor editor program, located in the Database_editor_new folder of the OPENBOX SF-50 software section.

Before starting programming, it is necessary to transfer the database from the device to the computer. To do this, turn on the device, connect a USB flash drive to the USB port. Execute MENU - System - Save to USB,

Exit the menu by pressing the MENU button until the current channel appears, or until the main menu picture, if there are no channels yet, and remove the USB flash drive. Insert the USB flash drive into the computer.
Run the Editor.exe program from the Database_editor_new folder and open the image on the USB flash drive in it.

When prompted to select a database, select User Data Base.

Click OK. Select All Services, a list of all scanned and saved TV, radio and service channels available in the database will open.

Edit channels as you wish, for example, leave only open channels.
On the computer keyboard, hold down the Shift button, press the Down Arrow and select the channels you want to delete. Press Delete to delete the selection.

To edit the satellite settings, select All Services - Satellite Information - EUTELSAT W4, W7, press ENTER.

If necessary, edit the values \u200b\u200bin Antenna 1.
To delete a transponder, go to the unnecessary one and press the Delete button on the computer keyboard, confirm the selected action.

To add a transponder, stand on the satellite name, press the right mouse button and select Add Information (or by highlighting the satellite, press the Insert button on the keyboard).

Enter the data for the new transponder, taking them, for example, on the website lyngsat.com.

Click OK, make sure that the transponder is registered.

To add a satellite, go to the Satellite Information line, press the Insert key on the keyboard and enter the parameters of the new satellite.

close the editor program, remove the drive.
Insert the drive into the OPENBOX SF-50 device, follow the sequence MENU - System - Update from USB, select the "SAT & TP List" mode.

Select Start. Confirm your intentions.

The device will update the base and reboot itself. After rebooting, you will have to set the Russian menu language in a new way in the settings. Reset device to factory settings.
Exit the settings menu by pressing the MENU button twice. Press the OK button on the current channel and make sure that the channel list is edited.

You can also make sure to edit the list of transponders and satellites.
The programming is complete.

But it is not enough just to physically connect the device to the computer, you also need to establish data exchange between them. How to choose a port and organize a connection? A few years ago, the standard solution was to use a COM port. By the way, various specialists still install 8, 16, or even 32 COM ports on industrial computers (there is a whole category of various PCI expansion cards for serial ports, controllers, etc.). Thus, if you need to connect several external devices with an RS-232 interface, you may need expensive adapters and exotic expansion cards, which, according to the old tradition, sail to Russia for weeks on ships. By the way, the name of the usual adapter "DB9m / DB25f adapter" at the manager of a computer store can only cause irritation.

What is a HID device

Now almost all devices are connected to a computer via a USB interface. Therefore, many new PCs do not have a COM port at all.

USB interface is a typical solution for pairing a new external device with a computer, more precisely, it is a HID interface based on the USB 1.1 protocol.

Although many believe that the HID (Human Interface Device) interface is intended solely for the keyboard, mouse and joystick, it is suitable for many solutions related to pairing external devices and a computer.

If the user needs to carry out low-speed data exchange (up to 64 kbps) and at the same time it is desirable to reduce the time spent on the tedious development of his own drivers, then HID is quite suitable for him. The output will be a simple and quite modern solution based on a standard software USB interface with guaranteed support on all common software platforms.

HID device properties

From the point of view of organizing software support for a HID device, everything looks quite attractive: to work under Windows, you can quickly create an understandable compact code based on ready-made proven algorithms. In this case, the developer will have a lot of time to implement his own upper-level data exchange protocol, since the required level of abstraction has already been organized due to the HID protocol (see table). In addition, it is easy for a programmer to debug a written exchange protocol (of course, if there is a working HID device) - due to the relative rigidity of the protocol itself, it is quite easy to develop a program to support the device by a computer. Still would! The creator of the HID device has already undertaken a lot of work.

Organization of data exchange between the HID device and the computer

To describe the interaction of a HID device with a computer, we will use the term "host". In this case, it is understood as a control device in the general physical architecture of interaction over the USB protocol. So, all ports on a computer are hosts. You can connect to them various USB devices (flash drives, mice, webcams, cameras, etc.) that do not have a host. The host provides discovery, connection, disconnection, device configuration, and statistics collection and power management.

The HID device can set the polling rate itself, during which it is found out if there is any new data in it. This means that even at such a low level, the programmer can trust the system, since the polling rate and other communication parameters must be predefined in the HID device controller program. This distinguishes the HID protocol from the general description of USB 1.1 or USB 2.0, which does not have strict requirements for the organization of the protocol. However, for specific tasks that require an increased level of security, it can be quite difficult to get rid of cyclic polls, when almost the same data blocks are constantly transmitted.

Features of programming HID devices

HID devices have special descriptors. When the host determines that the device belongs to the HID class, it transfers control to the appropriate driver. It is assumed that further data exchange is under his direction.

On Windows, the HidServ system service is responsible for accessing HID devices. More details about the functions of queries to HID devices and other features of working with the HID driver are described in the work by P. V. Agurov “USB interface. Practice of use and programming "(St. Petersburg: BHV-Petersburg, 2005).

Programming HID devices at the "top level"

The hard life of Pascal application programmers is made easier by the proven HID module. PAS, a frontend for hid. dll (Hid User Library - as specified in the file properties). The file comments indicate that it is based on the hidsdi.h and hidpi.h modules from Microsoft. And the HID file itself. PAS is part of the JEDI () package.

To work with a HID device in the Delphi for win32 environment, the TJvHidDeviceController component is used, which is a convenient global manager for accessing HID devices. And already on its basis, you can get an object instance for working with a specific device.

Basic properties and events of the TJvHidDeviceController component

Let's take a closer look at the TJvHidDeviceController component. The OnArrival event is triggered when a HID device arrives (connects) to the system; access to the device is provided in the handler of this event through an instance of the TJvHidDevice class. The simple event OnDeviceChange responds to a change in the state of the device; it only signals changes in the system. The OnDeviceData event fires when data comes from one of the HID devices and sends the following to the handler: HidDev: TJvHidDevice; - the device from which the data was received;

The OnDeviceDataError event notifies about a data transfer error by passing the HidDev parameters to the processing procedure: TJvHidDevice; - HID device and Error: DWORD; - error code. The OnDeviceUnplug event notifies that a device has been removed from the list of installed devices on the system. The event handler types for Plug and Unplug are the same (in the source text: TJvHidUnplugEvent \u003d TJvHidPlugEvent). An object of the TJvHidDevice class corresponding to the HID device is passed to the handler.

The OnEnumerate event is intended for a sequential enumeration of the HID devices available in the system by calling the Enumerate method, that is, in the event handler, the found devices are sequentially transmitted as objects. This event is forcibly triggered by the Enumerate method, which is used to "guide" existing HID devices through the handler, for example, when the state of HID devices is revised at the initiative of the host (computer).

The OnRemoval event fires when a device is physically removed from the system and has the same TJvHidUnplugEvent handler type as for OnDeviceUnplug. The CountByProductName function returns the number of devices that match the product name specified in the argument, and CountByVendorName returns the manufacturer name specified in the argument.

Basic properties and events of the TJvHidDevice class

The TJvHidDevice class is a virtual representation of a single HID device. A new object of this class can be obtained, as already mentioned, from the OnArrival or OnEnumerate event. The functionality of the TJvHidDeviceController and TJvHidDevice classes is partially duplicated, since the first of them integrates a common toolkit for working with a set of HID devices available in the system and a mechanism for accessing one of them. A device can be uniquely identified by its SerialNumber, ProductName, and VendorName properties. You can use the OnData event to get information about the arrival of data using such an object. Data is sent via the WriteFile method (in the strict sense, via a function). WriteFile is a wrapper around the WriteFile (kernel32) system function.

To control the fact that the device has been removed, you should assign your handler to the OnUnplug event. Before starting data exchange with a HID device, you need to make sure that such an exchange is possible using HasReadWriteAccess. This class even has a separate OnDataError event for a communication error.

And now let's look at code fragments from a "live" project that implements a test client application for organizing data exchange with a non-standard device - plastic chip cards based on HID. In the struggle for realism, the author took the liberty of not throwing out "unnecessary" technological code connections from the listings.

The ScanDevices method (Listing 1) is designed to initiate the process of searching the system for the required HID device. Most of the code, with the exception of the call to the Enumerate method, is optional and provides flexibility for the application, for example, so that the ability to work on a non-HID interface can be added to the same test program. The AddError method displays debug information in the window while the program is running.

Listing 2 shows an OnEnumerate event handler for finding the required external device. For simplicity, we will assume that the program can work with only one device of the type it needs.

Before considering the further implementation of the project, it is necessary to tell a little about the accepted format of the upper-level data exchange, that is, about the structure designed to be an intermediary between the methods of receiving and transmitting data and the specific applied problem being solved. The fact is that here the developer is given the opportunity to realize his creative abilities. Rather, developers, because the process of creating a new protocol is very often two-way, and the first violin is played by the one who finds it more difficult to implement the exchange algorithm. In general, whatever the exchange protocol, it is always nice to make each software entity as visual and self-sufficient as possible, even to the detriment of some generally accepted traditions. For the best solution is the one that will be implemented in a short time with minimal binding to the software environment and with great opportunities for further development. Based on these principles, an upper-level exchange protocol was created, where the main concept is “command”. Listing 3 shows how much the author loves string data, which has repeatedly saved him when debugging program modules. How wonderful that we have a String type at all! All protocol commands are divided into categories (classes), within which there is a command code that uniquely characterizes its purpose. The edParam parameter is used to send data to the device, and the edAnswerData parameter contains the data received from the device. The string type of the described record members allows you to freely and clearly manipulate data in the format of a HEX string. And what is most pleasant, the format of the described record ideologically stands somewhere in the middle between its immediate purpose and various forms of its representation (INI, HEX, XML, etc.)

Command execution, that is, sending data to the device, is implemented using data packets that are 8 bytes long (Listing 4). This length is not the only solution, such a choice is dictated by the requirements of the upper-level protocol and in each case may be different. This is, as they say, a matter of taste. The strange IsUSBMode flag in the ExecuteCommand method (Listing 5 on PC Disk World) is left as a reminder that instead of using USB, we might need to use a COM port or some other interface. At the beginning of the sent data group, a synchro series of an arbitrary format (for example, 3E3E3E2B) is transmitted to the device, informing the device that it has completely legal data at its input. Let me remind you that in this case we are talking not so much about HID as about a specific upper-level protocol, ideologically separated from the hardware and intended for solving special applied problems.

A specially created event OnNewInputData is used in the GetDataExecutor handler for the data received from the device (8 bytes packet) to transfer the initially processed data for further processing, with an indication of their old and new values \u200b\u200b(Listing 6 on "PC-Disk World"). Thus, the events of the arrival of raw data and the indication for further processing are decoupled, allowing the addition of some specific warning algorithm at an early stage of erroneous, repeated or unnecessary input information.

The examples of working with a HID device presented here illustrate the general idea of \u200b\u200bthe article - the relative ease of programming non-standard HID devices using Delphi.

Let's start with a minimum:
include 18f2455 - library for the used MK
--
enable_digital_io () - switching all inputs to digital mode
--
aliasButton ispin_B7 - since we have a button connected, we will declare it
pin_B7_direction \u003d input - the button works for us to enter
--
- one line - and we have everything you need to work with USB CDC
include usb_serial - library for working with usb
--
usb_serial_init () - --initialize USB CDC
forever loop- the main cycle, is performed constantly
usb_serial_flush () - usb update. This procedure performs all the necessary
- actions to maintain connection with PC
end loop

By compiling this code, writing the resulting HEX file to the MK using a bootloader and starting the device, you can watch how a new device is defined in the system: Virtual com-port.

Now that the device is already working, we will teach it to communicate.

To read the received byte there is a function usb_serial_read (byte ) : boolean. If there is a received byte, it stores it in the specified variable and returns true, otherwise it returns false.

There is a procedure to send a byte usb_serial_data... It is disguised as a variable, so to send a byte it is enough to assign it the value of the sent byte.

Let's declare a byte-sized variable before the main loop, in the main loop we will check for the presence of received bytes, and, if any, send them back.

include 18f2455
--
enable_digital_io ()
--
aliasButton ispin_B7
pin_B7_direction \u003d input
--
--
include usb_serial
--
usb_serial_init ()
var bytech - we declare a variable
forever loop- main loop
usb_serial_flush ()
if(usb_serial_read (ch)) then- if a byte is received, it will be written to ch
usb_serial_data \u003d ch - send the received byte back
end if
end loop

We compile, hold down the button, juggle the power supply, launch the bootloader, change the firmware, run it.
The device was again detected in the system, now we need software in order to test the operation of the device.

While we do not have our own, we use a ready-made terminal: I used the RealTerm program.
We open the port with the desired number and send the data.


And we get back what we sent. So everything is working as it should.

Software

So, our microcontroller is able to receive bytes and immediately send them back. Now let's write our own software for communicating with him (I will use Delphi).

We create a new project, scatter the necessary components in the form:
SpinEdit1 - for specifying the port number
Button1 - to establish a connection
Button2 - to disconnect the connection
SpinEdit2 - for decimal byte input
Button3 - to send a byte
Memo1 - to display the received information.

As mentioned above, you need to work with the com-port in the same way as with a regular text file: using the CreateFile, WriteFile and ReadFile functions.

In order not to go into details, let's take a ready-made library for working with the com-port: ComPort.

We hang the necessary task on each button and get the final code:

unit Unit1;

interface

Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin, ComPort;

Type
TForm1 \u003d class (TForm)
SpinEdit1: TSpinEdit;
Button1: TButton;
Button2: TButton;
SpinEdit2: TSpinEdit;
Button3: TButton;
Memo1: TMemo;
procedure OnRead (Sender: TObject; ReadBytes: array of Byte);
procedure Button1Click (Sender: TObject);
procedure Button2Click (Sender: TObject);
procedure FormDestroy (Sender: TObject);
procedure Button3Click (Sender: TObject);
private
(Private declarations)
Port: TComPort;
public
(Public declarations)
end;

var
Form1: TForm1;
num: integer;
implementation

Procedure TForm1.Button1Click (Sender: TObject);
begin
Port: \u003d TComPort.Create (SpinEdit1.Value, br115200); // create a connection
Port.OnRead: \u003d OnRead; // create a stream to read the received data
Button2.Enabled: \u003d true; // activate the button for closing the connection
end;

Procedure TForm1.Button2Click (Sender: TObject);
begin
Port.Free; // close the connection
Button2.Enabled: \u003d false; // disable the button
end;

Procedure TForm1.Button3Click (Sender: TObject);
begin
if Button2.Enabled then Port.Write ();
end;

Procedure TForm1.FormDestroy (Sender: TObject);
begin
if Button2.Enabled then
Port.Free;
end;

Procedure TForm1.OnRead (Sender: TObject; ReadBytes: array of Byte);
var
i: integer;
begin
for i: \u003d Low (ReadBytes) to High (ReadBytes) do // go through the array of received bytes
begin
Memo1.Text: \u003d Memo1.Text + "." + InttoHex (ReadBytes [i], 2); // add its HEX value to the window
inc (num); // count the number of received bytes
end;
if num\u003e 10 then begin
Memo1.Lines.Add (""); // wrap the line
num: \u003d 0;
end;
end;

We start, establish a connection, send bytes:

So our simplest terminal is ready to work with the simplest usb device.

As you can see, reading and writing is done with dynamic byte arrays.

By processing the information received, it is possible to compose the necessary exchange protocol suitable for the current task.

include 18f2455
--
enable_digital_io ()
--
aliasButton ispin_B7
pin_B7_direction \u003d input
--
--
include usb_serial
--
usb_serial_init ()
var bytech
var bytei - we declare the second variable
forever loop- main loop
usb_serial_flush ()
if(usb_serial_read (ch)) then- if a byte is received, perform the necessary actions
casech of - iterate over the byte number
0: usb_serial_data \u003d 0xff
1: usb_serial_data \u003d Button - sending button state
OTHERWISE block- if received something else
for16 usingi loop- send 10 bytes with data
usb_serial_data \u003d ch + i - from ch to ch + 15
end loop
end block
end case
end if
end loop

Additional features

If you stop at this, you get a regular article with a detailed description of an example of using the library, of which there are enough on the Internet. Therefore, I will add a little more in-depth information.

Simplifying sending data

Sending information one byte at a time is not always convenient. A library can often come in handy print... It contains procedures for sending data of all possible lengths in all possible formats: byte, hex, dec, bin, boolean, which can simplify the output of data in a program.
\u003e include print
...
var dworddata
print_dword_hex (usb_serial_data, data)

The name of all commands can be found in the library file.

Waiting for PC connection

If, before starting the main cycle of the microcontroller, it is necessary to first establish a connection with the PC, then you can add lines before it
while(usb_cdc_line_status () \u003d\u003d 0x00) loop
end loop

Bind the port number to the device

If you leave everything as it is, the system will allocate the first free port number with each new connection. And this means that you will always have to monitor him.
In order to prevent this from happening, you need to assign a unique serial number to the device before connecting the usb library:
The number can be of any length and contain different characters.
const byteUSB_STRING3 \u003d
{
24 , - array length
0x03, - bDescriptorType
"0" , 0x00,
"1" , 0x00,
"2" , 0x00,
"3" , 0x00,
"4" , 0x00,
"5" , 0x00,
"6" , 0x00,
"7" , 0x00,
"8" , 0x00,
"9" , 0x00,
"X" .0x00
}

Change the device name to your own

You can change the device name visible in the system before installing the drivers by declaring an array with a name like the serial number, this must be done before connecting the USB library.
const byteUSB_STRING2 \u003d
{
28 , --
0x03, - bDescriptorType
"D" , 0x00,
"e" , 0x00,
"m" , 0x00,
"o" , 0x00,
" " , 0x00,
"B" , 0x00,
"o" , 0x00,
"a" , 0x00,
"r" , 0x00,
"d" , 0x00,
" " , 0x00,
"=" , 0x00,
")" .0x00
}

But alas, after installing the drivers, the device will change the name to the one specified in the .inf file, so we will change the name there too


DESCRIPTION \u003d "Demo CDC"

We organize automatic device connection

Alas, there are no direct ways to complete this task, so you have to contrive.

First of all, you need to assign your device a unique manufacturer and product value in order to easily identify it among hundreds of other standard CDC firmwares.
VID and PID are issued for money, so let's go along the path of the Chinese: we will quietly take for ourselves obviously free values.

Firmware:
You must declare two variables in the firmware before connecting the USB library

const wordUSB_SERIAL_PRODUCT_ID \u003d 0xFF10
const wordUSB_SERIAL_VENDOR_ID \u003d 0xFF10

Instead of FF10, you can insert any two words (2 bytes). The end result is contained in the attached archive.

Drivers:
Since the drivers are not intended for our combination of VID and PID, let's add our values \u200b\u200bto the .inf file manually:


% DESCRIPTION% \u003d DriverInstall, USB \\ VID_FF10 & PID_FF10


% DESCRIPTION% \u003d DriverInstall, USB \\ VID_FF10 & PID_FF10

Software:
To catch the events of connecting / disconnecting a device, connect the ComponentUSB library. I don't consider it necessary to explain every line: all changes can be seen in the attached project.

Result

It is difficult to see in the screenshot, but the send button is active only when there is a connected device, while every 50ms the program sends a request to receive the state of the button (which, however, is wrong, because pressing the button must be processed on the MC).

As you can see, organizing data exchange between MK and PC via USB is not the most difficult task. The resulting connection can be used not only for final purposes: it is also suitable for debugging a program. After all, sending the results of calculations, the current states of registers and variables to a computer is much clearer than blinking a pair of LEDs in Morse code.

And finally: I advise you to look into the source code of the mood lamp. There you can find a pretty good option for processing the received data to organize a convenient exchange protocol.

As already mentioned, Windows operating systems provide software support for the operation of devices connected to the USB bus. Processing streams of data from USB devices at the operating system level is performed by a stack of standard drivers that perform the basic functions of managing and exchanging data between all USB devices and the system.

If you need to write software for a USB device that would expand its data processing capabilities, then you can choose one of three possible paths:

write your own device driver that would provide all the necessary control and data exchange functions, and a program that would interact with this driver in user mode. In this case, you can completely do without the standard system drivers;

write a filter driver that provides the required functionality but sits in the driver stack above the system drivers. Thus, all standard processing functions would be performed by the USB drivers installed by the system, and additional functions would be provided by your filter driver, with which the user program would interact;

use free libraries of functions and drivers

to access the USB device.

In most cases, software access to a USB device may be required if the device performs a very specific function. For example, “electronic oscilloscopes” or data acquisition systems have been developed on the basis of USB, to work with which it is necessary to have access to the device itself. In most of these cases, you can use free libraries of functions that will work in almost all popular programming environments. For example, under the auspices of GNU, software known as LibUsb has been developed, which includes the necessary drivers and function libraries to run on Windows and Linux operating systems. These function libraries are very popular and allow you to quickly develop programs that interact with your device through a set of standard functions. This eliminates the need to write your own device driver, which significantly saves time.

In addition, most users are not familiar with the driver development methodology,

and this is a very complex area of \u200b\u200bprogramming, so the availability of such freely redistributable software will be of invaluable help to a wide range of users. On the basis of the LibUsb project, wrappers have been developed for working with Visual Basic .NET and C # .NET, the most popular of which is LibUsbDotNet, also developed under the auspices of free software. Despite the seeming complexity of programming USB devices, the listed software makes this task so easy that even beginners can do it. Let's look at practical examples of how to work with your USB devices, and start with the LibUsb software package. By the way, the above software can be downloaded free of charge from www.sourceforge.net or from numerous duplicate sites.

How to work with LibUsb USB function libraries? The library is built this way

zom so that you can perform basic operations related to the USB device:

identification or, in other words, enumeration. When performing this operation, the devices connected to the USB bus are detected, which is done using the corresponding functions of the libusb library;

obtaining device parameters (device identifiers, data on the manufacturer and device characteristics), for which the library has a number of functions;

opening, closing, reading and writing data, sending commands. The USB device, just like other objects in the file system, can be accessed by writing by reading, which is done using the corresponding library functions.

All of these features can be implemented by calling the corresponding libusb functions, but they will not be listed here, since it would take too much space; we will see how to use some of these functions

Figure: 6.10

Location of the libusb0.sys driver in the device driver stack

tions on practical examples. Readers can find a description of all functions in the corresponding documentation. Let me remind you that we are considering the use of libusb functions in Windows operating systems.

When installing the distribution kit with libusb in Windows operating system, the libusb0.sys filter driver is installed in the system. This driver will sit at the top of the system driver stack, which is easy to see, for example, by looking at the driver information for any USB device (Figure 6.10).

In addition, to access the driver from user programs, the libusb0.dll library is installed into the system, using which you can develop user programs.

Figure: 6.17

Application window view when uninstalled

USB devices from the system