查看: 2029|回复: 0

手把手学习NXP S08P 系列单片机(六)

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3300

    主题

    6547

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32030
    最后登录
    2024-4-26
    发表于 2020-9-10 16:00:09 | 显示全部楼层 |阅读模式
    手把手学习NXP S08P 系列单片机(六)



    手把手学习NXP S08P系列单片机的往期内容有:






    S08P系列微控制器是NXP推出的基于8位内核的微控制器,该系列产品集成了丰富的外设,例如触摸传感接口(TSI)、EEPROM 和电机控制FlexTimer等。这一期将要向大家介绍的外设是外部中断(KBI)和串口(SCI)。
    本文中包含较多的代码,那些源代码都可以在NXP官网www.nxp.com/S08P-Lite或飞锐泰克官网www.free-tech.com.cn免费下载。本文是以S08PT60为例进行讲解,文中包含的寄存器描述等内容来源于该芯片的《参考手册》,请下载芯片的参考手册进行学习。


    外部中断(KBI)


    1,简介

    KBI(Keyboard Interrupt)中断模块也称为外部中断。当部分芯片引脚电平边沿变化的时候,程序就会从主函数中跳转到中断服务函数中去执行相应的代码,执行完成后,再继续执行主函数中的代码。


    S08PT系列总共有两个KBI模块,可以产生16个外部中断。参考开发板电路原理图,图上标有KBInPx的IO口就具有KBI功能。
    2,寄存器
    1.png

    3. 配置步骤
    配置寄存器KBI1 _SC,选择使用边沿模式或是电平模式,使能中断;
    配置寄存器KBI1_PE,使能管脚;
    配置寄存器KBI1_ES,边沿模式下选择检测上升沿或是下降沿;电平模式下选择检测高电平或是低电平;

    4. 代码
    功能演示:使用S08PT60的KBI1模块,演示按键SW2连接的KBI1P4中断:当SW2按下时,产生中断,在中断里翻转LED2的状态。
    1. /* 初始化外部中断
    2. * */
    3. void kbi_init(void)
    4. {
    5.         KBI1_SC =0x02; //使能中断;边沿触发
    6.         KBI1_PE =1<<4; //使能按键SW2引脚的KBI interrupt
    7.         KBI1_ES =1<<4; //选择检测上升沿
    8. }
    9. /*中断函数
    10. * */
    11. interrupt VectorNumber_Vkbi1 void  Kbi1_ISR(void)
    12. {
    13.         KBI1_SC_KBACK =1;//清除中断标志
    14.         PIN_LED2_PD =!PIN_LED2_PD;//中断产生后,翻转LED2的状态
    15. }
    复制代码
    串口(SCI)


    1,简介
    S08P系列的SCI不仅具有常见串口的功能,比如配置波特率、1位或2位停止位长度、8位或9位数据位长度,还具有常见串口没有但却非常有用的一些功能,例如:接收空闲中断等各类中断、发送数据取反、硬件产生奇偶校验位、硬件检查奇偶校验位等等。


    2,寄存器
    2.png

    3. 配置步骤
    配置寄存器SCIx_BD,配置波特率;
    配置寄存器SCIx_C1,选择数据帧格式;
    配置寄存器SCIx_C2,选择接受或者发送

    4. 代码
    S08PT60系列共有3个SCI模块:SCI0、SCI1、SCI2。本次使用SCI2进行两种不同方式的数据传输演示。

    功能演示(1):不使能中断,使用查询等待的方式发送数据。这种方式编程简单,但是当传输的数据量较大或者传输速度较快时,可能发生丢失数据帧的现象。

    串口函数
    1. /* 初始化串口2
    2.    * busCLKHz 总线时钟
    3.    * baudrate 波特率
    4.    * */
    5. void Init_SCI2(dword busCLKHz,dword baudrate)
    6. {
    7.     /* 打开模块时钟 */
    8.     SCG_C3 |= SCG_C3_SCI2_MASK;//总线时钟
    9.     /* 设置波特率,SCIx_BD = BUSCLK/16/baudrate *
    10.     SCI2_BD =(2*busCLKHz/(16*baudrate)+1)/2;
    11.     SCI2_C1  = 0;     // 设置数据帧格式:8bit data, no parity, 1 stop bit
    12.     SCI2_C2  = 0x0C;  // 使能发送和接收功能
    13. }
    14.   /* 查询等待的方式接收一个字符串
    15.    * */
    16. char TERMIO_GetChar3(void)
    17.   {
    18.     char dummy;
    19. /* 查询接收数据寄存器是否有数据 */
    20.     while(( SCI2_S1 & SCI2_S1_RDRF_MASK) !=SCI2_S1_RDRF_MASK);
    21.     dummy = SCI2_S1;//清除标志位
    22.     dummy = SCI2_D;
    23.     return dummy;//返回数据寄存器中的接收到的数据
    24.   }
    25.   /* 查询等待的方式发送一个字符串
    26.    * */
    27.   void TERMIO_PutChar3(char send)
    28.   {
    29.     char dummy;
    30.     /* 等待发送区数据寄存器为空 */
    31.     while(!( SCI2_S1 & SCI2_S1_TDRE_MASK));
    32.     /* 清标志位 */
    33.     dummy = SCI2_S1;
    34.     /* 给寄存器写入要发送的数据 */
    35.     SCI2_D  = send;
    36.   }
    复制代码
    主函数
    1. ......
    2. #include "uart.h"
    3. ......
    4. char test_str[]="Hello world\n";//准备发送的字符串
    5. void main(void) {
    6.         char* ptr;
    7. ......
    8.         Init_SCI2(16000000, 115200);//串口初始化
    9. ......
    10.         for(;;) {
    11.                 delay_ms(1000);
    12.                 if ((TERMIO_GetChar3()=='d'))
    13.                 {
    14.                 ptr=test_str;
    15.                 while(*ptr)
    16.                 {
    17.                         TERMIO_PutChar3(*ptr);
    18.                         ptr++;
    19.                 }
    20.                 PIN_LED1_PD =!PIN_LED1_PD;
    21.                 }
    22.         }
    23. }
    复制代码
    功能演示(2):使能中断,通过环形缓存区接收和发送数据。这种方式编程相对复杂,但能防止丢包现象。
    本次演示的带缓冲区的串口收发程序包含了两个环形缓冲区,即发送缓冲区和接收缓冲区。发送数据时,先将数据存在发送缓冲区,然后再通过串口发送;接收数据时,先将接收的数据存在接收缓冲区,然后再进行读取。
    环形队列有两个索引,一个指向队列头,是缓冲区的可读数据,一个指向队列尾,是缓冲区的可写地址。两个索引一直顺时针循环移动即可对缓冲区进行数据读写操作。下图一个长度为4的环形缓冲区示意图:
    3.png

    发送数据:先移动写索引,把要发送的数据全部加入到发送缓冲区中,接着打开TIE中断,芯片进入中断程序,开始移动读索引,发送数据,直到整个字符串发送完毕,此时写索引与读索引重合。

    接收数据:当一个数据接收完毕后,先将数据存入接收缓冲区而不处理,并且写索引的值加1。等到处理器空闲,再从缓冲区读取这些数据并做处理。
    初始化
    初始化函数和代码1中相同,但在主函数中初始化完成后需要打开中断。

    1. Init_SCI2(16000000, 115200);
    2. SCI2_C2_RIE =1;//串口初始化后要打开中断
    复制代码
    缓存与中断
    1. #include "uart_buff.h"
    2. #include "port.h"

    3. /* 接收和发送缓存区的长度
    4. * 只支持2的n次方,2 4 8 16 32 64 128 256 ... */
    5. #define BUFF_LEN 4
    6. /* 缓存索引加1,超出缓存区长度后回0 */
    7. #define INDEX_ADD(xx) {xx =(xx + 1) & (BUFF_LEN - 1);}
    8. /* 接收缓存 */
    9. static uint8_t  rxbuff[BUFF_LEN];
    10. static uint16_t rxbuff_w_index; //接收缓存写索引
    11. /* 发送缓存 */
    12. static uint8_t  txbuff[BUFF_LEN];
    13. static uint16_t txbuff_w_index; //发送缓存“写”索引
    14. static uint16_t txbuff_r_index; //发送缓存“读”索引


    15. /* 发送函数
    16. * 数据写入发送缓存,并开中断
    17. * data 数据指针
    18. * len  数据长度
    19. * */
    20. void Sci2_tx(uint8_t* data,uint8_t len)
    21. {
    22.         /* 写入数据 */
    23.         while(len--)
    24.         {
    25.                 txbuff[txbuff_w_index]=*data;
    26.                 data++;
    27.             INDEX_ADD(txbuff_w_index);
    28.         }
    29.         /* 打开中断 */
    30.         SCI2_C2_TIE =1;
    31. }

    32. /* 发送中断函数 */
    33. interrupt VectorNumber_Vsci2tx void  Sci2tx_ISR(void)
    34. {
    35.         volatile uint8_t s1 =SCI2_S1;
    36.        
    37.         if(s1 & SCI1_S1_TDRE_MASK)
    38.         {
    39.                 /* 缓存区还有数据,继续发送 */
    40.                 if(txbuff_r_index != txbuff_w_index)
    41.                 {
    42.                         SCI2_D = txbuff[txbuff_r_index];
    43.                         INDEX_ADD(txbuff_r_index);
    44.                 }
    45.                 else
    46.         /* 缓存区空,关闭中断 */
    47.                 {
    48.                         SCI2_C2_TIE =0;
    49.                 }
    50.         }
    51. }

    52. /* 接收中断函数 */
    53. interrupt VectorNumber_Vsci2rx void  Sci2rx_ISR(void)
    54. {
    55.         /* 先读 SCI2_S1 然后读SCI2_D可自动清楚中断标志位  */
    56.         volatile uint8_t s1 =SCI2_S1;
    57.         volatile uint8_t d;
    58.         if(s1 & SCI1_S1_RDRF_MASK)
    59.         {
    60.                 d =SCI2_D;
    61.                 /* 把接收到的数据存入接收缓存区 */
    62.                 rxbuff[rxbuff_w_index] =d;
    63.                 INDEX_ADD(rxbuff_w_index);
    64.                 /* 处理数据 */
    65.                 if(d == '#')
    66.                 {
    67.                         PIN_LED4_PD =!PIN_LED4_PD;
    68.                         rxbuff_w_index =0;
    69.                         Sci2_tx("RD",2);
    70.                 }
    71.         }
    72. }
    复制代码
    主函数
    1. ...
    2. #include "uart.h"
    3. #include "uart_buff.h"

    4. char test_str[]="123";
    5. void main(void) {
    6. ......
    7.         Init_SCI2(16000000, 115200);
    8.         SCI2_C2_RIE =1;//串口初始化后打开中断
    9. ......
    10.         for(;;) {
    11.                 delay_ms(1000);
    12.                 ptr=test_str;
    13.                 Sci2_tx(ptr,3);
    14.                 PIN_LED1_PD =!PIN_LED1_PD;
    15.         }
    16. }
    复制代码
    这是说明演示小视频:





    S08P系列产品


    S08P系列产品是基于恩智浦S08内核的5V 8位高性能微控制器,该系列基于恩智浦独特设计的5V平台,集成了PWM波输出、EEPROM、触摸接口、ADC、比较器等丰富的外设资源,可在2.7到5.5V电压下工作,提供卓越的抗干扰能力,可满足工业控制和人机交互等严苛应用环境中的抗干扰需求,并符合电器安全标准IEC60730。
    S08P系列包含了多种性能丰富,各具特色的子系列产品,用户可以根据不同的需求选择不同性能、不同性价比的产品。如需了解S08P系列不同型号产品的更多信息,请参看文章《8位S08P 5V MCU推荐选型》。

    飞锐泰克公司


    北京飞锐泰克科技有限公司是从事电子元器件代理、推广、技术支持及嵌入式产品开发的技术型科技公司。2009年得到世界知名的NXP公司授权,推广NXP MCU。飞锐泰克希望通过技术方面的服务,能够让客户更深入的了解NXP单片机产品的优越性能和便捷的开发平台,帮助客户有效的降低成本,迅速的提升利润空间。



    文章出处:恩智浦MCU加油站

    签到签到
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-26 20:25 , Processed in 0.130394 second(s), 22 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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