串口使用.docx
- 文档编号:6410899
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:18
- 大小:92.36KB
串口使用.docx
《串口使用.docx》由会员分享,可在线阅读,更多相关《串口使用.docx(18页珍藏版)》请在冰豆网上搜索。
串口使用
1、串口的初始化
在MTK平台上,串口的操作和常见的操作系统不太一样,串口句柄并不是以文件形式的出现,而是有点类似单片机的做法,即每个串口有固定的编号,串口的初始化不需要有类似Windows/Unix等打开设备文件的操作(实际上是有UART_Open这个函数的,不过我们没有用到,大概是底层硬件初始化会用到,这里我们简单的理解成不需要Open就好了),下面我们对照实际的初始化代码逐句讲解初始化所需要做的事情,如下所示:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//我们要用到的串口,uart_port1是枚举型数值,usb串口的编号
#defineHELLO_WORLD_UART_PORTuart_port1//手机接USB下载线的地方
//定义我们的应用所属系统的哪一个模块
//这里是MMI模块,实际上我更愿意称MMI为一个子系统,将我们的应用称为模块
#defineMOD_HELLO_WORLDMOD_MMI
//数据接收Buffer大小
#defineMAX_ECHO_PACKET_LEN128
//睡眠模式句柄
statickal_uint8ghSleepMode;
//我们要用到的串口之前的占用者
staticmodule_typegnOrigUartOwner;
statickal_boolgbUartInitialized=KAL_FALSE;
staticvoidinit_uart(void)
{
#ifdef__MMI_HELLOWORLD_ENABLED__
if(gbUartInitialized)
{
return;
}
ghSleepMode=L1SM_GetHandle();
//禁止休眠,休眠后串口收发会有问题
//问题:
如何做到串口唤醒?
FIXME
L1SM_SleepDisable(ghSleepMode);
//记录我们要用的串口的当前占有者
gnOrigUartOwner=UART_GetOwnerID(HELLO_WORLD_UART_PORT);
//下面我们申明要占用这个串口了
UART_SetOwner(HELLO_WORLD_UART_PORT,MOD_HELLO_WORLD);
//以上对串口占用的申明,我理解更多是一种编程者之间的约定
//当发现串口的占用者不是本程序所属模块时,说明我们申明占用之后
//又有其他模块申明占用同一个串口,此时如果收到数据应不予处理
//当然,也有可能同一模块的其他程序申明占用同一串口
//这需要在设计应用时统一协调,避免数据发生混乱
//设置波特率,缺省的起停位和校验为:
8,n,1,即8个数据位,1个停止位,无校验
UART_SetBaudRate(HELLO_WORLD_UART_PORT,UART_BAUD_115200,MOD_HELLO_WORLD);
//其他串口设定(如起停位、校验等)使用函数UART_ReadDCBConfig和UART_SetDCBConfig
//详细参数见结构体UARTDCBStruct
//注册一个事件钩子函数,当串口(任何)有数据到达时,我们的钩子函数将被调用
//注意,同一种事件同时只能注册一个钩子函数,因此:
//如果在我们的程序处理串口的同时还有其他程序要读取和处理(任何)串口数据,
//就必须由当前的钩子函数代为处理
//实际上我觉得系统底层可以改一下,改成Windows钩子的方式,可以挂多个,能够依次调用或跳过
SetProtocolEventHandler(mmi_HelloWorld_uart_readyToRead_ind_handler,MSG_ID_UART_READY_TO_READ_IND);
gbUartInitialized=KAL_TRUE;
#endif
}
2、从串口读数据
这里有两个相关的函数,第一个是上面初始化部分提到的钩子函数mmi_HelloWorld_uart_readyToRead_ind_handler,另外一个是读函数,函数体如下所示:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
staticvoidmmi_HelloWorld_uart_readyToRead_ind_handler(void*msg)
{
#ifdef__MMI_HELLOWORLD_ENABLED__
uart_ready_to_read_ind_struct*uart_rtr_ind=(uart_ready_to_read_ind_struct*)msg;
//检查一下端口以及所有者信息,不匹配的数据略过
//注意,作为例子程序,我们只是查看和处理我们关心的数据
//其他与此同时需要监听和处理串口数据的程序,须由相关的代码完成代理的工作
if(KAL_FALSE==gbUartEchoStarted||
HELLO_WORLD_UART_PORT!
=uart_rtr_ind->port||
MOD_HELLO_WORLD!
=UART_GetOwnerID(uart_rtr_ind->port))
{
//如果底层能做成钩子链,这里就可以调用钩子链的下一个钩子了
return;
}
gwLenUartBuffer=read_from_uart(gabyUartBuffer,sizeof(gabyUartBuffer),HELLO_WORLD_UART_PORT,MOD_HELLO_WORLD);
//呼叫数据处理部分
uart_echo_process();
#endif
}
staticU16read_from_uart(U8*pbyBuf,U16wLenMax,UART_PORThPort,module_typehOwner)
{
U16wLenAvail;
U16wLenRead;
U16wLenRet=0;
U8byStatus=0;
#ifdef__MMI_HELLOWORLD_ENABLED__
//收取数据,超出最大包长的数据将简单丢弃,这一层需要具体的应用协议做相应处理
while((wLenAvail=UART_GetBytesAvail(hPort)>0&&wLenRet { if(wLenAvail+wLenRet>wLenMax) { wLenAvail=wLenMax-wLenRet; } wLenRead=UART_GetBytes(hPort,(kal_uint8*)(pbyBuf+wLenRet),(kal_uint16)wLenAvail,&byStatus,hOwner); wLenRet+=wLenRead; } //读完之后,清除接收Buffer UART_ClrRxBuffer(hPort,hOwner); #endif returnwLenRet; } 3、向串口写数据 staticU8write_to_uart(U8*pbyBuf,U16wLenBuf,UART_PORThPort,module_typehOwner) { U16wSent=0; U8bRet=FALSE; #ifdef__MMI_HELLOWORLD_ENABLED__ //发送前清FIFO和Buffer,注意: 这一步必须做,否则收发会有问题 UART_Purge(hPort,RX_BUF,hOwner);//清除设备输入FIFO UART_Purge(hPort,TX_BUF,hOwner);//清除设备输出FIFO UART_ClrTxBuffer(hPort,hOwner);//清除发送Buffer UART_ClrRxBuffer(hPort,hOwner);//清除接收Buffer wSent=UART_PutBytes(hPort,(kal_uint8*)pbyBuf,(kal_uint16)wLenBuf,hOwner); #endif if(wSent==wLenBuf) { bRet=TRUE; } returnbRet; } 4、关闭串口 关闭串口实际上是将相关的设置改动恢复到之前的状态,不需要有close的动作,如下所示: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// staticvoidexit_uart() { #ifdef__MMI_HELLOWORLD_ENABLED__ if(gbUartInitialized) { //恢复成原有的端口占用者 UART_SetOwner(HELLO_WORLD_UART_PORT,(kal_uint8)gnOrigUartOwner); //允许休眠 L1SM_SleepEnable(ghSleepMode); gbUartInitialized=KAL_FALSE; } #endif } 5、下载测试 Makeremake一下->下载程序到手机->关闭下载工具->运行串口工具,打开USB下载线对应的串口,设定为115200,8N1->手机开机(此时下载线不要拔下,我们用的就是这个下载线测试的)->手机工具菜单->HelloWorld->手机左键启动串口Echo(启动后再按左键停止串口Echo)。 注1: 串口的部分在仿真器上模拟不了,链接的时候也会提示找不到相关函数符号。 注2: 在HelloWorld的串口Echo停止工作时我们也能偶尔看到串口会原样回显,这应该是其他程序在处理,不是我们的HelloWorld,我们的HelloWorld会将输入转成全大写再回显。 注3: 使用手机的USB下载口当作串口时,要用USB下载线进行连接,同时要注意相关的工程设置为以下: -------------- TSTConfig <无> <115200> PSConfig <115200> -------------- 设置方法: 待机界面下(拨号)输入*#3646633#(进入工程模式)->设备->"SetUART"->"UARTSetting" 程序运行后的电脑端截图如下: 我采用1ms定时发送“Hello,World! \r\n”,每毫秒15字节的速度,接收比发送多,这是因为启动Echo时,我有送一个串“HelloWorldUartEchoExampleStarted! \r\n”(40字节)过来,不过接收多出的部分应该不止10个字节(1928380–1928370),应该是40个字节,数据似乎有部分丢失(刚好2个包,15*2=30=40-10),应该是电脑端发送太快的原因(115200/(8+1)/1000=12.8字节/毫秒,小于15,而且还有数据处理和echo的时间),这样的响应速度算相当不错了。 6、完整的C程序 下面贴出比较完整的HelloWorld.c程序,供大家参考,由于时间的关系,开发心得暂时到此为止,感谢华禹公司及其兄弟公司的支持,感谢各位网友! ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include"stdC.h" #include"MMI_Features.h"/*编译开关会出现在这个由makeupdate生成的文件里面*/ #include"L4Dr.h" #include"L4Dr1.h" #include"AllAppGprot.h" #include"FrameworkStruct.h" #include"GlobalConstants.h" #include"EventsGprot.h" #include"mmiappfnptrs.h" #include"HistoryGprot.h" #include"HelloWorldProt.h" #include"HelloWorldTypes.h" #include"HelloWorldDefs.h" #include"MainMenuDef.h" #include"wgui_categories.h" #include"Unicodexdcl.h" #include"gui_data_types.h" #include"Uart_sw.h" //我们要用到的串口,uart_port1是枚举型数值,usb串口的编号 #defineHELLO_WORLD_UART_PORTuart_port1//手机接USB下载线的地方 //定义我们的应用所属系统的哪一个模块 //这里是MMI模块,实际上我更愿意称MMI为一个子系统,将我们的应用称为模块 #defineMOD_HELLO_WORLDMOD_MMI //数据接收Buffer大小 #defineMAX_ECHO_PACKET_LEN128 //外部函数申明,没有对应头文件,手动加吧 externmodule_typeUART_GetOwnerID(UART_PORTport); externvoidUART_ClrTxBuffer(UART_PORTport,module_typeownerid); externvoidUART_ClrRxBuffer(UART_PORTport,module_typeownerid); //本程序内部使用的函数申明 staticvoidinit_uart(void); staticvoidmmi_HelloWorld_uart_readyToRead_ind_handler(void*msg); staticU16read_from_uart(U8*pbyBuf,U16wLenMax,UART_PORThPort,module_typehOwner); staticU8write_to_uart(U8*pbyBuf,U16wLenBuf,UART_PORThPort,module_typehOwner); staticvoidexit_uart(); staticvoidstart_uart_echo(void); staticvoiduart_echo_process(void); staticvoidstop_uart_echo(void); //睡眠模式句柄 statickal_uint8ghSleepMode; //我们要用到的串口之前的占用者 staticmodule_typegnOrigUartOwner; statickal_boolgbUartInitialized=KAL_FALSE; statickal_boolgbUartEchoStarted=KAL_FALSE; staticU16gwLenUartBuffer=0; staticU8gabyUartBuffer[MAX_ECHO_PACKET_LEN]; staticvoidinit_uart(void) { #ifdef__MMI_HELLOWORLD_ENABLED__ if(gbUartInitialized) { return; } ghSleepMode=L1SM_GetHandle(); //禁止休眠,休眠后串口收发会有问题 //问题: 如何做到串口唤醒? FIXME L1SM_SleepDisable(ghSleepMode); //记录我们要用的串口的当前占有者 gnOrigUartOwner=UART_GetOwnerID(HELLO_WORLD_UART_PORT); //下面我们申明要占用这个串口了 UART_SetOwner(HELLO_WORLD_UART_PORT,MOD_HELLO_WORLD); //以上对串口占用的申明,我理解更多是一种编程者之间的约定 //当发现串口的占用者不是本程序所属模块时,说明我们申明占用之后 //又有其他模块申明占用同一个串口,此时如果收到数据应不予处理 //当然,也有可能同一模块的其他程序申明占用同一串口 //这需要在设计应用时统一协调,避免数据发生混乱 //设置波特率,缺省的起停位和校验为: 8,n,1,即8个数据位,1个停止位,无校验 UART_SetBaudRate(HELLO_WORLD_UART_PORT,UART_BAUD_115200,MOD_HELLO_WORLD); //其他串口设定(如起停位、校验等)使用函数UART_ReadDCBConfig和UART_SetDCBConfig //详细参数见结构体UARTDCBStruct //注册一个事件钩子函数,当串口(任何)有数据到达时,我们的钩子函数将被调用 //注意,同一种事件同时只能注册一个钩子函数,因此: //如果在我们的程序处理串口的同时还有其他程序要读取和处理(任何)串口数据, //就必须由当前的钩子函数代为处理 //实际上我觉得系统底层可以改一下,改成Windows钩子的方式,可以挂多个,能够依次调用或跳过 SetProtocolEventHandler(mmi_HelloWorld_uart_readyToRead_ind_handler,MSG_ID_UART_READY_TO_READ_IND); gbUartInitialized=KAL_TRUE; #endif } staticU16read_from_uart(U8*pbyBuf,U16wLenMax,UART_PORThPort,module_typehOwner) { U16wLenAvail; U16wLenRead; U16wLenRet=0; U8byStatus=0; #ifdef__MMI_HELLOWORLD_ENABLED__ //收取数据,超出最大包长的数据将简单丢弃,这一层需要具体的应用协议做相应处理 while((wLenAvail=UART_GetBytesAvail(hPort)>0&&wLenRet { if(wLenAvail+wLenRet>wLenMax) { wLenAvail=wLenMax-wLenRet; } wLenRead=UART_GetBytes(hPort,(kal_uint8*)(pbyBuf+wLenRet),(kal_uint16)wLenAvail,&byStatus,hOwner); wLenRet+=wLenRead; } //读完之后,清除接收Buffer UART_ClrRxBuffer(hPort,hOwner); #endif returnwLenRet; } staticU8write_to_uart(U8*pbyBuf,U16wLenBuf,UART_PORThPort,module_typehOwner) { U16wSent=0; U8bRet=FALSE; #ifdef__MMI_HELLOWORLD_ENABLED__ //发送前清FIFO和Buffer,注意: 这一步必须做,否则收发会有问题 UART_Purge(hPort,RX_BUF,hOwner);//清除设备输入FIFO UART_Purge(hPort,TX_BUF,hOwner);//清除设备输出FIFO UART_ClrTxBuffer(hPort,hOwner);//清除发送Buffer UART_ClrRxBuffer(hPort,hOwner);//清除接收Buffer wSent=UART_PutBytes(hPort,(kal_uint8*)pbyBuf,(kal_uint16)wLenBuf,hOwner); #endif if(wSent==wLenBuf) { bRet=TRUE; } returnbRet; } staticvoidexit_uart() { #ifdef__MMI_HELLOWORLD_ENABLED__ if(gbUartInitialized) { //恢复成原有的端口占用者 UART_SetOwner(HELLO_WORLD_UART_PORT,(kal_uint8)gnOrigUartOwner); //允许休眠 L1SM_SleepEnable(ghSleepMode); gbUartInitialized=KAL_FALSE; } #endif } staticvoidmmi_HelloWorld_uart_readyToRead_ind_handler(void*msg) { #ifdef__MMI_HELLOWORLD_ENABLED__ uart_ready_to_read_ind_struct*uart_rtr_ind=(uart_ready_to_read_ind_struct*)msg; //检查一下端口以及所有者信息,不匹配的数据略过 //注意,作为例子程序,我们只是查看和处理我们关心的数据 //其他与此同时需要监听和处理串口数据的程
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 串口 使用
![提示](https://static.bdocx.com/images/bang_tan.gif)