Эмуляция интерфейса RS232-USB микроконтроллера PIC18

В этой стать будет представленный пример работы с USB портом микроконтроллера PIC18F4550 в режиме эмуляции интерфейса RS232 с использованием HI-TECH PICC компилятора и USB CDC библиотеки.

Так же данная библиотека отлично работает на PIC18F46J50 и на подобных камушках с компилятором C18!
Только в инициализацию нужно добавить обязательно: OSCTUNEbits.PLLEN=1;  //Включаем PLL

Так как этот пример есть урезаная версия большего проекта файл main.c у нас называется GPS_PIML.c

В этом файле вам нужно обратить на функцию USB_CDC_INTERRUPT();  которая находится в обработчике прерывания высокого приоритета так же на биты

INTCONbits.GIEH = 1;
INTCONbits.GIEL = 1;

которые включают прерывания. В основном цикле программы я жду пока на порте power_usb не появится высокий приоритет который говорит о том что был подключен USB шнурок и мы можем начинать работать с портом.

//Подключение модулей
#include #include
#include
#include
#include
#include

#include "ana.h"
#include "zdr.h"
#include "port.h"
#include "USB_CDC\USB_CDC.h"
#include "USB_CDC\USB.h"

// =========================================================
// ================ ВЕКТОРА ПРЕРЫВАНИЙ =====================
// =========================================================

static interrupt low_priority low_isr(void);
static interrupt high_isr(void);

#ifndef HI_TECH_C
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm GOTO high_isr _endasm
}

#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm GOTO low_isr _endasm
}

#pragma code /* return to the default code section */
#endif
// ----- ОБРАБОТЧИК ПРЕРЫВАНИЙ ВЫСОКОГО ПРИОРИТЕТА ----------

//#pragma interrupt high_isr

static interrupt high_isr(void)
{
USB_CDC_INTERRUPT();
}

// ----- ОБРАБОТЧИК ПРЕРЫВАНИЙ НИЗКОГО ПРИОРИТЕТА -----------

#pragma interruptlow low_isr

static interrupt low_priority low_isr(void)
{
// USB_CDC_INTERRUPT();
}

// ==========================================================

//***********************************************************
//*************** оснавная прорамма *************************
void main()
{

ADCON1 = 0b00001110;// AN0 только аналоговый вход
// ADCON2 = 0b00000001;

//-------- настройка портов ------------
TRISA = 0b11111111;
TRISB = 0b11100010;
TRISC = 0b11111111;
TRISD = 0b11111000;
TRISE = 0b00000111;
//--------------------------------------

// ------------------------------------------------------
INTCONbits.GIEH = 1;
INTCONbits.GIEL = 1;
// ------------------------------------------------------

led2 =0;

for(;;){

led=1;
zdr(50);

if(power_usb==1)
{
USB();
}

led=0;
zdr(950);

}
}

Вот и сама функция USB();  в которой мы принимаем и передаем данные в порт. Логика работы такая, ждем пока к нам не придет что-то если байт равен  CONNECT 0x01 то в ответ шлем «Ok» дальше ждем READ 0x10 если получили шлем в ответ число 31.


 

void USB(void)
{
unsigned char i;
unsigned char n;

USB_CDC_OPEN();

led =0;
led2 =1;

for(;;)
{

ByteCount = READ_FROM_USB_CDC(& USB_BUFF[0]); // пришло что-нибудь ???
//______________________________________________________________________
//____________________ CONNECT _________________________________________
if(ByteCount&&(USB_BUFF[0] == CONNECT))// передаем "Ok"
{

USB_BUFF[0] = 'O';
WRITE_TO_USB_CDC(& USB_BUFF[0], 1);
zdr(1);
USB_BUFF[0] = 'k';
WRITE_TO_USB_CDC(& USB_BUFF[0], 1);

}
//____________________ CONNECT _________________________________________
//______________________________________________________________________
//______________________________________________________________________
//____________________ передаем данные _________________________________
if(ByteCount&&(USB_BUFF[0] == READ))//
{

USB_BUFF[0] = 31;
WRITE_TO_USB_CDC(& USB_BUFF[0], ByteCount);
//zdr(1);

}

//____________________ передаем данные _________________________________
//______________________________________________________________________
if(power_usb ==0)
{
USB_CDC_CLOSE();
zdr(200);
led2 =0;
break;
}
}
}

При сборке проекта использовался компилятор HI-TECH PICC-18 STD 9.52.

Конфигурационные биты микроконтроллера:

configurationBits

Еще была написанная простейшая программа на Microsoft Visual Studio 2010 для наглядной демонстрации работы данного проекта.

Test USB PIC18

Листинг программы:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.IO.Ports;

namespace Test_USB_PIC18
{
public partial class Test : Form
{
//string bufer;
byte[] b = new byte[128];

string s_port = "COM1";
string s_BR = "115200";

private delegate void MyDelegate(string value);

public Test()
{
InitializeComponent();

comboBox_port.SelectedItem = s_port;//присваеваем значения
comboBox_BR.SelectedItem = s_BR;//присваеваем значения
}

private void Form1_Load(object sender, EventArgs e)
{
try
{
string[] availablePorts = SerialPort.GetPortNames();
foreach (string port in availablePorts)
{
comboBox_port.Items.Add(port);
}
comboBox_port.Text = comboBox_port.Items[0].ToString();

}
catch (Exception e9)
{
MessageBox.Show(e9.Message);
}
}

//при закрытии приложения закрываем порт
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
serialPort1.Close();
}
catch (Exception e16)
{
MessageBox.Show(e16.Message);
}
}

private void button_connect_Click(object sender, EventArgs e)
{
int i;
byte[] b = new byte[128];

try
{
if (serialPort1.IsOpen == true)
{
MessageBox.Show("Порт уже открыт!");
}
else
{

serialPort1.PortName = comboBox_port.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox_BR.Text);
serialPort1.Open();
richTextBox1.Text = "Порт открыли.\r";

serialPort1.Write(new byte[] { 0x01 }, 0, 1);//CONNECT

Thread.Sleep(100);//задержка

for (i = 0; i < 100; i++)
{
if (serialPort1.BytesToRead > 0)//если есть что читать, читаем
{
serialPort1.Read(b, 0, b.Length);
}
//Thread.Sleep();
}

//если от устройства получили "Ok" значит можно считывать данные
if ((b[0] == 'O') &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; (b[1] == 'k'))
{
richTextBox1.Text += "Подключились к устройству.\r";
button_read.Enabled = true;
}

}

}
catch (Exception e1)
{
MessageBox.Show(e1.Message);
}
}

private void button_disconnect_Click(object sender, EventArgs e)
{
serialPort1.Close();
richTextBox1.Text += "Порт закрыли.\r";
}

private void button_read_Click(object sender, EventArgs e)
{
int i;
byte[] b = new byte[128];//буфер

try
{
//button_read.Enabled = false;

//___________________ Tel ____________________________________________________________
serialPort1.Write(new byte[] { 0x10 }, 0, 1);//READ

Thread.Sleep(100);

for (i = 0; i < 100; i++)
{
if (serialPort1.BytesToRead > 0)//если есть что читать, читаем
{
serialPort1.Read(b, 0, b.Length);

}
//Thread.Sleep();
}

richTextBox1.Text += "Ответ: " + b[0] + "\r";//(Encoding.ASCII.GetString(b));

//____________________________________________________________________________________
}

catch (Exception e15)
{
MessageBox.Show(e15.Message);
}
}

private void serialPort1_My_DataReceived()
{
if (InvokeRequired) //проверяем, в каком мы потоке
{//если во вроричном, то через Invoke, создавая делегат
Invoke(new MyDelegate(ReadString), serialPort1.ReadExisting().ToString());
return;
}
//Если нет, то напрямую.
ReadString(serialPort1.ReadExisting().ToString());
}

private void ReadString(string value)
{
//bufer += value ;
//label1.Text += bufer.Length.ToString();
//label1.Text += bufer;
}
}

}

Файлы проекта:

MPLAB Test_PIC18_USB

Драйвер USB RS232

Microsoft Visual Studio Test_USB_PIC18