OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8366|回复: 3
打印 上一主题 下一主题

[新人试水] LPC1768 RTT_Nano3 Shell

[复制链接]

55

主题

134

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
388
金钱
388
注册时间
2018-8-7
在线时间
55 小时
跳转到指定楼层
楼主
发表于 2019-3-14 16:38:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Fillmore 于 2019-3-14 16:50 编辑

RT Nano V3初级教程第二章 Finsh Shell.pdf (785.16 KB, 下载次数: 13)
第二章 Finsh Shell
在搞Finsh Shell之前先要搞定一个串口通讯,至少要保证能收数据能发数据。

2.1 串口
由于使用的是LPC1768,直接参考一下BSP下的LPC176x工程的写法,之前我在网上看教程,都是从STM32讲起的,更可笑的是,我在做串口程序的时候,是从STM32的串口程序改过来的。。。好浪费时间呀。。。
当时参考 “RT thread 设备驱动组件之USART设备”这个文档做的,前人种树,后人乘凉呀。现在知道学习方法了没有?先去看一下BSP里面有没有对应的例程序,有的话,直接参考。不懂了再看网上相关的文章,之前俺的学习路线出了点差错,不过还好,跑起来了。

现在,我们在前一节的基础上,添加UART。

先来看一下uart.c这个文件里面都有什么鬼,定义了一个结构体,几个函数,如图2-1所示。


图2-1 uart.c结构图
注意了,以前总是说static定义的函数只能内部使用,外部不能用呢??什么鬼??实际上是错误的,之前也做过实验,通过指针的方法是可以访问的,可能应当改写成“static定义的函数,不能直接被外部的文件显式调用,指针方法可以调用”。

串口0各函数的作用如表2-1所示,其中rt_hw_uart_init函数是供外部调用的初始化函数,它主要任务是完成设备接口函数的绑定,并将设备注册,如图2-2所示。

表2-1 串口0各函数的作用
[mw_shl_code=c,true]UART0_IRQHandler        串口0的中断函数,接收数据到缓冲区
rt_uart_init                        串口0的初始化函数
rt_uart_open                        串口0的打开函数,开中断
rt_uart_close                        串口0的关闭函数,关中断
rt_uart_read                        串口0的读取函数,从缓冲区读取数据
rt_uart_write                        串口0的发送函数
rt_hw_uart_init                        将以上函数与设备结构体绑定,并注册[/mw_shl_code]

图2-2 串口初始化函数
首先定义了一个结构体指针uart,这个指针指向实体uart_device,然后对实体进行赋值,其中那个parent就是rt_device,这个取的名字也很讨厌,为什么不直接写成device这样的名字呢?可以自己改的,嘿嘿,我也懒得去改,知道是它就成。最后一句,注册到RTT。注意了,这里只是小学生刚来注册报名登记而已,什么事情都还没有干,相当于还没有安排座位(真正的初始化),还无法开始听课(数据读取和写入操作)。

再说一下那个结构体是怎么回事吧。
[mw_shl_code=c,true]struct rt_uart_lpc
{
    struct rt_device parent;
    /* buffer for reception */
    rt_uint8_t read_index, save_index;
    rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE];
} uart_device;[/mw_shl_code]

rt_device这个是系统定义好的结构体,用户需要自定义设备结构体时,都从这个地方去扩展,把它放到最前面是为了方面取地址和强制内型转换使用(强制转换会不会把数给弄坏了?以前我也这样想。我们换一个思路来看这个问题,那个东东原原本本在那里,我们用一个相机拍个照(读取数据),照片是有参考坐标的,不同的坐标读取不同的值,在上面画上网格,格子大小不同,读取的数据就会不同,但是原有的数据不会变,除非你写入。)

2.2 添加串口文件
在工程目录下建立一个文件夹Drivers,并将LPC176x下的uart.c和uart.h复制过来,然后在工程添加Drivers目录,将uart.c添加进去。如图2-3中的1所示。然后添加头文件的目录,如图2-3中的2和3操作,将头文件目录包含进来,如图2-4所示。


图2-3添加uart.c/添加头文件包含目录



图2-4添加uart.c/添加头文件包含目录

注意一下,44行,这里对两个宏进行了判断,只有打开了这两个开关,下面的代码才参考编译呢。

5.jpg(7.83 KB, 下载次数: 5)


图2-5编译条件

2.3 打开串口支持
查找一下那两个宏定义在什么地方,悲剧的是,RT_USING_UART0个宏没有定义的地方,另一个宏在rt_config.h里面有,但是长相不好看呢。先看一新旧配置文件的对比图吧,如图2-6、2-7所示。




      

图2-6 新版配置文件                                                                           
没有那个Device选择的地方了,怎么办,看一下里面都写了什么,如图2-7所示。RTE_USING_DEVICE也没有找到定义呢,要用怎么办?手动添加吧。




   

图2-7 配置文件信息
编译,出错了哦,NND,这个Nano 3改进得怎么这么不人性化呢?看一下是什么?说是没有定义
Drivers\uart.c(56): error:  #20: identifier "RT_UART_RX_BUFFER_SIZE" is undefined
怎么办?继续添加,参考一下以前的代码,定义是这个样子的:
#define RT_UART_RX_BUFFER_SIZE  (RT_CONSOLEBUF_SIZE >> 1)
至为什么呢?我也不知道,没有看文档,用PP想一下,那个定义之后有64个字节,从键盘输入超过64个字节的将会是什么指令呢?哥都不让它这么多输入,浪费老子空间。最后配置文件如图2-8所示。


图2-8 手动修改配文件

再编译,没有错误了。接下来要添加Finsh Shell了。

2.4 Finsh Shell支持
OMG,算了放张图就好了,如图2-9所示。(这里实在是太简单了,无法用语言表达,请看图。)

11.jpg(112.08 KB, 下载次数: 5)
图2-9添加Finsh Shell

编译,没有错误哦。

2.5 检查一下
查找一下初始化函数,如图2-10所示。坑货,怎么没有调用呀?




图2-10查找一下调用情况

注意,编译没有错误,并不代码程序执行没有错误,不然怎么会出现BUG呢?编译成功只能说明,语法没有问题,符合编译器的逻辑。

2.6 Shell使用uart0
输出口选择设备“uart0”,注意了,这里的uart0不是指LPC上的串口0,指的是名字为uart0的那个设备。所以,不要以为只能是串口哦,别的接口,可能也是可以用的,当然,我没有试过,机会留给大家。


图2-11选择uart0进行输出


添加到board.c中去,如图2-12所示。


图2-12添加初始化
下载试用
图2-13 下载设置

使用PuTTY查看运行结果
怪了,怎么这样也可以运行?记得之前在2.1.1时,如果没有进行Linker的相关设置时,是不能运行的,这个RT_thread进行改进了?反正我是不清楚啦,我也刚玩不久。但是屏上显示乱码呢,怎么回事?是不是和那个Linker设置有关呢?啥子情况呢?而且每次启动都不一样哦。先展示一下启动时的图片,如图2-14所示。



图2-14运行时有乱码

2.9 试着添加Linker设置

如图2-15所示。添加 --keep*.o(.rti_fn.*)   --keep *.o(FSymTab)

图2-15Linker设置
编译运行,乱码还在。说明不是这个问题,位置都不是固定的,那就肯定是波特率不准造成的啦,修改一下试试。


2.10 修改波特率偿试"


2018-3-18 02:16 上传



图2-16降低波特率
结果是,好了!想骂人不?哪个瓜娃子写的底层驱动呀?BSP不准哦!!!修改这个是治标不治本的法子哦!

2.11 为什么会有乱码
说实话,今天我也第一次使用Rt_thread中提供的uart驱动,没有想到它会有这个问题。以前在做项目时,我遇到过几次,最后都归结于使用现成驱动代码造成的后果,波特率不准。来,看一下它的初始化长什么样,如图2-17。


图2-17 串口初始化关键部分

为什么会不准呢?两种波特率上都会有误差,为什么115200bps时就显示出来了呢?上面的除法表示什么?1bit位要跑几个时钟嘛,对比一下就知道了,哪个相对误差大,误差大的肯定会出错,当然,当其字符数最在很少的情况是不容易显现出来。有一种误差叫累计误差,误差只有累计到一定程度时,才表现出来。简单地理解为时钟不一样通信时,前肯定没有问题,但是累计到一定程序时,出现大偏差,周而复始。

2.12 修正函数. b. t. A9 U- z/ U- I) n
基实NXP官方给出了波特率修正的文档,可以肯定的说,写那个驱动的小哥,一定没有看过那个文档,或是看过了,没有在意。这里为大家提供一个函数,直接使用就可以了。


[mw_shl_code=c,true]//add by hjb 精准波特率
voidrt_uart_precise_baudset(rt_uint32_t bps, rt_uint8_t *m_fdr, rt_uint32_t *m_fdiv)
{
    typedef struct
    {
       rt_uint8_t Div: 4; //分频
       rt_uint8_t Mul: 4; //乘数
    } rt_uart_dcm_tbl;

    //1-[000-999]+\,
    rt_uart_dcm_tbl const tbl[] =
    {
       { 0, 1 }, { 1, 15}, { 1, 14}, { 1, 13},
       { 1, 12}, { 1, 11}, { 1, 10}, { 1, 9 },
       { 1, 8 }, { 2, 15}, { 1, 7 }, { 2, 13},
       { 1, 6 }, { 2, 11}, { 1, 5 }, { 3, 14},
       { 2, 9 }, { 3, 13}, { 1, 4 }, { 4, 15},
       { 3, 11}, { 2, 7 }, { 3, 10}, { 4, 13},
       { 1, 3 }, { 5, 14}, { 4, 11}, { 3, 8 },
       { 5, 13}, { 2, 5 }, { 5, 12}, { 3, 7 },
       { 4, 9 }, { 5, 11}, { 6, 13}, { 7, 15},//-----------4*9
       { 1, 2 }, { 8, 15}, { 7, 13}, { 6, 11},
       { 5, 9 }, { 4, 7 }, { 7, 12}, { 3, 5 },
       { 8, 13}, { 5, 8 }, { 7, 11}, { 9, 14},
       { 2, 3 }, { 9, 13}, { 7, 10}, { 5, 7 },
       { 8, 11}, { 11, 15}, { 3, 4 }, { 10, 13},
       { 7, 9 }, { 11, 14}, { 4, 5 }, { 9, 11},
       { 5, 6 }, { 11, 13}, { 6, 7 }, { 13, 15},
       { 7, 8 }, { 8, 9 }, { 9, 10}, { 10, 11},
       { 11, 12}, { 12, 13}, { 13, 14}, { 14, 15},
    };

    rt_uint8_t i = 0, k = 0, j = 0;
    rt_uint8_t m_err[72] = {0};

    rt_uint32_t fDiv, uDLest;
    rt_uint32_t uartClock = SystemCoreClock / 4; // 外设时钟与内核时钟的比例

    float fFRest = 1.5;// tFRest = 1.5, tAbs, min;


    if (uartClock % (16 * bps) == 0) // PCLK / (16*bps)为整数
    {
       m_fdr[0] = 0x10;// 关闭分频器
       m_fdiv[0] = (uartClock >> 4) / ( bps );
       return;
    }

    k = 0xff;
    for(i = 0; i < 72; i++)            //遍历
    {
       uDLest = (uint32_t)(uartClock * tbl.Mul / (16 * bps * (tbl.Mul + tbl.Div)));
       fFRest = (float)(uartClock * tbl.Mul) / (float)(16 * bps * uDLest * (tbl.Mul + tbl.Div));     //频率相对偏差
       fDiv = (uint32_t)((fFRest - 1) * 10000);
       if(fDiv > 0xff)
       {
           m_err = 0xff;
       }
       else
       {
           m_err = fDiv;
       }

       if(m_err < k)
       {
           k = m_err;     //得到误差最小的那个
           j = i;
           m_fdr[0] = tbl[j].Div | (tbl[j].Mul << 4);
           m_fdiv[0] = uDLest;
       }
    }
}
//[/mw_shl_code]


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

55

主题

134

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
388
金钱
388
注册时间
2018-8-7
在线时间
55 小时
2#
 楼主| 发表于 2019-3-14 16:52:34 | 只看该作者
本帖最后由 Fillmore 于 2019-3-14 16:54 编辑

[mw_shl_code=c,true]/*-----------------------------------BEGIN-------------------------------------*/
//add by hjb 精准波特率
voidrt_uart_precise_baudset(rt_uint32_t bps, rt_uint8_t *m_fdr, rt_uint32_t *m_fdiv)
{
    typedef struct
    {
       rt_uint8_t Div: 4; //分频
       rt_uint8_t Mul: 4; //乘数
    } rt_uart_dcm_tbl;
    //1-[000-999]+\,
    rt_uart_dcm_tbl const tbl[] =
    {
       { 0, 1 }, { 1, 15}, { 1, 14}, { 1, 13},
       { 1, 12}, { 1, 11}, { 1, 10}, { 1, 9 },
       { 1, 8 }, { 2, 15}, { 1, 7 }, { 2, 13},
       { 1, 6 }, { 2, 11}, { 1, 5 }, { 3, 14},
       { 2, 9 }, { 3, 13}, { 1, 4 }, { 4, 15},
       { 3, 11}, { 2, 7 }, { 3, 10}, { 4, 13},
       { 1, 3 }, { 5, 14}, { 4, 11}, { 3, 8 },
       { 5, 13}, { 2, 5 }, { 5, 12}, { 3, 7 },
       { 4, 9 }, { 5, 11}, { 6, 13}, { 7, 15},//-----------4*9
       { 1, 2 }, { 8, 15}, { 7, 13}, { 6, 11},
       { 5, 9 }, { 4, 7 }, { 7, 12}, { 3, 5 },
       { 8, 13}, { 5, 8 }, { 7, 11}, { 9, 14},
       { 2, 3 }, { 9, 13}, { 7, 10}, { 5, 7 },
       { 8, 11}, { 11, 15}, { 3, 4 }, { 10, 13},
       { 7, 9 }, { 11, 14}, { 4, 5 }, { 9, 11},
       { 5, 6 }, { 11, 13}, { 6, 7 }, { 13, 15},
       { 7, 8 }, { 8, 9 }, { 9, 10}, { 10, 11},
       { 11, 12}, { 12, 13}, { 13, 14}, { 14, 15},
    };
    rt_uint8_t i = 0, k = 0, j = 0;
    rt_uint8_t m_err[72] = {0};
    rt_uint32_t fDiv, uDLest;
    rt_uint32_t uartClock = SystemCoreClock / 4; // 外设时钟与内核时钟的比例
    float fFRest = 1.5;// tFRest = 1.5, tAbs, min;
    if (uartClock % (16 * bps) == 0) // PCLK / (16*bps)为整数
    {
       m_fdr[0] = 0x10;// 关闭分频器
       m_fdiv[0] = (uartClock >> 4) / ( bps );
       return;
    }
    k = 0xff;
    for(i = 0; i < 72; i++)            //遍历
    {
       uDLest = (uint32_t)(uartClock * tbl.Mul / (16 * bps * (tbl.Mul + tbl.Div)));
       fFRest = (float)(uartClock * tbl.Mul) / (float)(16 * bps * uDLest * (tbl.Mul + tbl.Div));     //频率相对偏差
       fDiv = (uint32_t)((fFRest - 1) * 10000);
       if(fDiv > 0xff)
       {
           m_err = 0xff;
       }
       else
       {
           m_err = fDiv;
       }
       if(m_err < k)
       {
           k = m_err;     //得到误差最小的那个
           j = i;
           m_fdr[0] = tbl[j].Div | (tbl[j].Mul << 4);
           m_fdiv[0] = uDLest;
       }
    }
}
//

/*-----------------------------------BEGIN-------------------------------------*/[/mw_shl_code]


用法:

图2-18修正函数用法


@# s2.13 115200bps再测试
我的天呢,没有搞定!!!而且运行得还更惨了,输出了,怎么回事!
俺说过,要改波特别率是不是?PC上的软件是不是没有改过来?改过来再试试,是不是完美了?

2.14 俺的Finsh Shell 显示东西少
怎么函数是干什么的都没有显示呢?在rt_config.h中添加 #define FINSH_USING_DESCRIPTION



图2-19

效果如图2-20所示。

图2-20带功能提示的Shell

2018-3-18 02:16 上传



图2-20带功能提示的Shell

2.15 Linker的设置要不要?
我在测试时,发现Linker上没有设置,RT3也能跑Finsh Shell。有遇到问题的是在2.1.1上,没有添加linker设置时,“msh>”这个死活不出来,编译什么的都没有问题。我也没有去细看RT3的修改说明,如果没有特别的要求要去掉的话,建议还是将linker的设置留下来比较稳妥。
<<<这条还是请大师们给个回复吧>>>

回复 支持 反对

使用道具 举报

109

主题

5564

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10581
金钱
10581
注册时间
2017-2-18
在线时间
1916 小时
3#
发表于 2019-3-15 09:55:15 | 只看该作者
帮顶~~
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
339
金钱
339
注册时间
2019-7-17
在线时间
39 小时
4#
发表于 2021-2-19 11:06:00 | 只看该作者
了解下,谢谢
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-8-27 11:12

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表