本帖最后由 南信大瑜 于 2012-4-21 21:16 编辑
首先,我要感谢大叔,能给我这
个学习芯唐M0的机会,我会记录自己的学习过程,与大家分享,由于我也是初学者,所以如果大家发现我的笔记有什么错误之处,希望大家及时指正。
今天已经是收到大叔板子的第五天了,在这五天里,我了解了NCU120的一些基本知识,我发现芯唐的固件库使用起来非常的方便,相比STM32的固件库来说,配置简单,固件库函数非常容易看懂,非常容易上手。下面言归正传,来开始我的第一个程序:USB控制LED灯。
1.
为什么要学习USB呢?
USB的应用已经非常广泛,像打印机、U盘、数码相机、手机等等都采用USB接口,我感觉USB已经成为了现在消费电子,工业控制等领域不可缺少的一种接口。因此,我们要学习好USB。
2. 功能描述:
NCU120集成了一个全速USB2.0控制器和收发器,支持control/bulk/interrupt/isochronous传输类型,我们可以使用它来与PC机进行通信。我的第一个程序就是要通过PC机控制助学板上四个LED的亮灭。
3. 如何开始?
我个人感觉USB协议很复杂,我以前看过USB协议,但看到一半就放弃了,因为看不懂,越看越不懂。有时候光看协议,人会受不了的,最好的办法就是通过实验,来体会,来分析。
学习USB的入门程序应该就是HID设备了吧。
HID(Human Interface Device)人机接口设备类别是Windows最早支持的USB类别。由其名称可以了解HID设备是计算机直接与人交互的设备,例如键盘、鼠标和游戏杆等。不过HID设备不一定要有人机接口,只要符合HID类别规范,就都是HID设备。
实现HID设备不需要我们自己编写驱动程序,这使USB通信变的简单了,但是HID设备的缺点是传输速度较慢,只适合数据传输较慢的场合。
4.MDK工程分析。
int main(void)
{
System_init(); //系统初始化函数
Gpio_init(); //初始化IO口函数
Uart_init(); //初始化串口函数
printf("\r\n");
printf("------------------------------------------\r\n");
printf("--- NCU120 Board USB_Hid Demo By Gwgj ---\r\n"); //打印开发板相关信息
printf("------------------------------------------\r\n");
HID_MainProcess(); //HID设备处理函数,在HID_API.c中定义
}
void System_init(void)
{
UNLOCKREG(); //由于一些寄存器具有写保护功能,所以在写寄存器前要首先
//进行解锁
SYSCLK->WRCON.XTL12M_EN = 1; //使能外部12M晶振,也就是把PWRCON寄存器的XTL12M_EN位置1
DrvSYS_Delay(5000); //延时一段时间,等待外部12M晶振稳定
DrvSYS_Open(48000000); //打系统时钟设置为48MHZ,以进行USB通信
LOCKREG();
}
void Gpio_init(void)
{
DrvGPIO_Open( E_GPA, 2, E_IO_OUTPUT ); //把LED1的端口设置为输出
DrvGPIO_Open( E_GPA, 3, E_IO_OUTPUT ); //把LED2的端口设置为输出
DrvGPIO_Open( E_GPA, 4, E_IO_OUTPUT ); //把LED3的端口设置为输出
DrvGPIO_Open( E_GPA, 5, E_IO_OUTPUT ); //把LED4的端口设置为输出
}
void Uart_init(void)
{
STR_UART_T sParam; //定义一个STR_UART_T类型的结构体
DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC, 0); //把UART的时钟设置为外部12M晶振
/* Set UART Pin */
DrvGPIO_InitFunction(E_FUNC_UART0); //初始化UART0对应的引脚
/* UART Setting */
sParam.u32BaudRate = 115200; //设置波特率为115200
sParam.u8cDataBits = DRVUART_DATABITS_8; //设置数据位为8位
sParam.u8cStopBits = DRVUART_STOPBITS_1; //设置停止位为1位
sParam.u8cParity = DRVUART_PARITY_NONE; //设置无奇偶校验位
sParam.u8cRxTriggerLevel= DRVUART_FIFO_1BYTES; //设置接收FIFO触发等级为1字节
DrvUART_Open(UART_PORT0,&sParam); //通过刚才配置的sParam参数来设置UART0
}
int32_t HID_MainProcess(void)
{
int32_t i32Ret = E_SUCCESS;
E_DRVUSB_STATE eUsbState;
i32Ret = DrvUSB_Open(0); //初始化USB设备,包括初始化USB SRAM,初始化状态等
if (i32Ret != E_SUCCESS)
return i32Ret;
while (1)
{
_DRVUSB_ENABLE_MISC_INT(0); //禁止 USB-related 中断
_DRVUSB_ENABLE_FLDET_INT(); //使能 float-detection 中断
// 等待USB连接
while (1)
{
// Order here is significant.
// Give a chance to handle remaining events before exiting this loop.
eUsbState = DrvUSB_GetUsbState();//获取USB状态
//DrvUSB_DispatchEvent();
if (eUsbState >= eDRVUSB_ATTACHED &&
eUsbState != eDRVUSB_SUSPENDED)
{
break; //如果USB已经连接,跳出循环,结束等待
}
}
//初始化HID设备,并把输入和输出报告定向到HID_GetInReport和HID_SetOutReport两个函数
//这两个函数非常重要,我们就是要在HID_GetInReport和HID_SetOutReport两个函数中实现自己的功能,实现数据传输
HID_Init((void *)HID_GetInReport, (void *)HID_SetOutReport);
// 使能USB中断 INTEN_WAKEUP,INTEN_WAKEUPEN,INTEN_FLDET,INTEN_USB和INTEN_BUS
_DRVUSB_ENABLE_MISC_INT(INTEN_WAKEUP | INTEN_WAKEUPEN | INTEN_FLDET | INTEN_USB | INTEN_BUS);
// 查询和处理USB事件
while (1)
{
eUsbState = DrvUSB_GetUsbState(); //获取USB状态
DrvUSB_DispatchEvent();//分发,处理USB事件
if (eUsbState == eDRVUSB_DETACHED) //如果USB断开了,跳出循环,重新等待USB链接
{
printf("USB Disconnected...\r\n");
break;
}
}
// Disable USB-related interrupts.
_DRVUSB_ENABLE_MISC_INT(0); //禁止USB-related中断
}
}
//HID_SetOutReport函数用于处理输出报告
//我们在这里分析上位机发送的数据,并根据相应的数据进行相应的操作
//收到 1 时:点亮LED 1
//收到 2 时:点亮LED 2
//收到 3 时:点亮LED 3
//收到 4 时:点亮LED 4
//收到 5 时:熄灭LED 1
//收到 6 时:熄灭LED 2
//收到 7 时:熄灭LED 3
//收到 8 时:熄灭LED 4
void HID_SetOutReport(uint8_t *pu8EpBuf)
{
uint8_t i;
uint32_t u32Size = (uint32_t)pu8EpBuf[1]; //pu8EpBuf[1]为收到数据的长度,由于我们上位机中每次都只发送一个字节,
//所以在这里不需要对数据的长度进行判断,如果上位机中发送的数据长度不是恒定的
//就要首先获取pu8EpBuf[1],再做相应的处理了
uint8_t cmd=pu8EpBuf[2]; //pu8EpBuf[2]就是我们收到的上位机传来的数据了
switch(cmd) //根据上位机发送的数据来进行点亮和熄灭LED的操作
{
case 1:
DrvGPIO_ClrBit(E_GPA,2);
break;
case 2:
DrvGPIO_ClrBit(E_GPA,3);
break;
case 3:
DrvGPIO_ClrBit(E_GPA,4);
break;
case 4:
DrvGPIO_ClrBit(E_GPA,5);
break;
case 5:
DrvGPIO_SetBit(E_GPA,2);
break;
case 6:
DrvGPIO_SetBit(E_GPA,3);
break;
case 7:
DrvGPIO_SetBit(E_GPA,4);
break;
case 8:
DrvGPIO_SetBit(E_GPA,5);
break;
default:
break;
}
}
//下位机的程序就结束了,由于芯唐提供了USB固件库,因此我们自己只写了几行代码就OK了,呵呵。
5.上位机程序分析。
虽然小弟以前也学过MFC,但是几年没用,已经忘的差不多了,今天就先不用MFC了,先建立一个命令行的工程,测试一下系统的功能,日后再改成MFC吧,真后悔当时没有好好学MFC啊。
开发环境为VS2005。
#include "stdafx.h"
#include "conio.h"
#include "Hid.h"
int _tmain(int argc, _TCHAR* argv[]) //主函数
{
CHidCmd io; //定义一个CHidCmd类型的对象
unsigned char cmd[]={0x00}; //定义一个数组,数组中存放要发送的数据
unsigned long Length;
char user_cmd=0;
printf("----------------------------------------------\n");
printf("-- NUC120助学板 USB HID Demo By 南信大瑜 --\n"); //打印一些相关信息
printf("----------------------------------------------\n");
printf("\n");
printf("->请进行功能选择:\n");
//打印一些帮助信息
printf("1 打开led1\n");
printf("2 打开led2\n");
printf("3 打开led3\n");
printf("4 打开led4\n");
printf("5 关闭led1\n");
printf("6 关闭led2\n");
printf("7 关闭led3\n");
printf("8 关闭led4\n");
printf("9 退出程序\n");
if(!io.OpenDevice(0x051A,0x511B)) //打开HID设备,第一个参数为VID,第二个参数为PID
{
printf("->USB 设备打开失败,请检查助学板是否正确连接\n");
user_cmd='9';
}
else
{
printf("->USB 设备打开成功\n");
}
while(user_cmd!='9') //如果用户输入‘9’,退出程序
{
user_cmd=getch();
switch(user_cmd) //如果用户输入的是'1'-'8',则通过USB发送相应命令到助学板
{
case '1':
cmd[0]=0x01;
printf("\n");
printf("-->打开LED 1\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '2':
cmd[0]=0x02;
printf("\n");
printf("-->打开LED 2\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '3':
cmd[0]=0x03;
printf("\n");
printf("-->打开LED 3\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '4':
cmd[0]=0x04;
printf("\n");
printf("-->打开LED 4\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '5':
cmd[0]=0x05;
printf("\n");
printf("-->关闭LED 1\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '6':
cmd[0]=0x06;
printf("\n");
printf("-->关闭LED 2\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '7':
cmd[0]=0x07;
printf("\n");
printf("-->关闭LED 3\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '8':
cmd[0]=0x08;
printf("\n");
printf("-->关闭LED 4\r\n\n");
io.WriteFile((const char *)&cmd,sizeof(cmd),&Length,2000);
break;
case '9':
printf("-->程序退出\n\n");
default:printf("\n");
printf("-->输入错误,请重新输入 >__< \n");
printf("\n");
break;
}
printf("->请进行功能选择:\n");
printf("1 打开led1\n");
printf("2 打开led2\n");
printf("3 打开led3\n");
printf("4 打开led4\n");
printf("5 关闭led1\n");
printf("6 关闭led2\n");
printf("7 关闭led3\n");
printf("8 关闭led4\n");
printf("9 退出程序\n");
}
io.CloseDevice(); //关闭设备
return 0;
}
undefined
|
|