S12学习笔记

    技术2025-01-18  10

    把学习笔记整理一下,懒得忘了。看了很多网上的资料,但是终觉得记不住,水过鸭背,糊里糊涂,决定尝试把它从自己嘴里吐出来。另外由于暂时缺乏硬件,只能停留在知识点层面,应用程序以后再说了。

    ;>P.S.(任何资料都是google所得,如有雷同,纯粹抄袭)

    PIT (Periodic Inerrupt Timer):

     

    如图,实际上就是一个8位计数器产生一个时钟信号,提供给下一个16位计数器计数,当溢出后就产生中断。公式:time-out period=(PITMTLD+1)*(PITLD+1)/fBUS

     

    各个寄存器中,

    PITMUX用来为416位计数器选择各自的时钟(接上哪一个8位计数器)。PITMLDn8位计数器的预存值,同理,PITDL则为16位计数器的预存值,而PITCNn为当前计数值。

    PITTFPITINTE分别为溢出标志位以及溢出中断使能位。

    PITCE是使能各个16位计数器通道。

    PITFLT是用来强迫16位计数器进行reload

    PITCFLMT用来强迫8位计数器进行reload,并且其中有一个PITE这个总使能标志位。

    总的来说,PIT就是像它英文所描述那样,通过自减计数直到零而溢出来周期产生中断的Module

    TIMER

     

    核心:为16位可编程计数器,其时钟源来自一个预分频器,S12拥有8输入捕捉/匹配输出通道、一个脉冲累加器

    什么叫输入捕捉呢---就是说,首先选择相应的引脚作为输入引脚,当sense到有效的边沿触发后,将timer16位计数器的数值转移到TCx寄存器中。(TCx就是相应引脚的一个装数的东东)。当然,当事件发生后,通过相应设置可以触发中断。

    什么是比较输出?---就是上面说的那个TCNT计数器跟TCx寄存器中的数值相比较,若果TCNT计数匹配到TCx,并且OCPDx置零,则可以根据TCTL12OMxOLx在相应引脚输出东东。同理,当事件发生后,通过相应设置可以触发中断。

    PA脉冲累加器?-------通过PAMOD来选择两种工作模式,一种是事件计数模式:PEDGE定义的

    有效边沿后则PACNT计数加一,并且通过PAVOFPAVOI标志位来进行溢出中断。另一种是门时间计数(不知道是不是这样翻译O(_)O~ Gated Time Accumulation Mode),就是在检测到PEDGE定义的电平后,PACNT divided-by-64 clock进行不断计数,直到随之的下一边沿。简单的说就是搞到那个电平延长了多久。

    TIMER的中断:-----主要有三种,一种TFLG1中的CxF标志任何输入捕捉还是匹配输出事件发生则相应位置高,配合TIE中的CxI进行中断使能;一种TFLG2主要是一个TOF(即从FFFF0000时则置高),这个配合TSCR2中的TOI可以中断。另一种PA通过PAVOFPAVOI标志位来进行溢出中断。

    时钟信号产生:TSCR2中有一个PR[2:0]来选择预分频,再加上PACTL中的CLK[1:0]进行时钟的

    选择,最终确定timer所用时钟信号

    零散分析:

    TSCR1存器是定时器模块的总开关,它决定模块是否启动以及在等待模式,BDM模式下定时器的工作状态。其中的TEN标志位用来使能这个计数器

    OCPD--使能匹配输出引脚是否connect

    TCTL1TCTL2决定了OCx(即匹配输出的方式)、而TCTL3TCTL4则配置输入捕捉的边缘触发方式

    Timer模块中的几个计数器或者说数值寄存器TCNT--储存Timer计数值;TCn--IC模式下,将Timer的计数值存下来,作为OC模式下,用来储存与Timer相比较的匹配值;PACNT--用来存放捕捉到的脉冲数量或者电平延续时间。

     

    另外注意OC7匹配输出的高高优先级):OC7匹配成功时可以改变、管理其他7个输出引脚的状态,即OC7MOC7D所决定的匹配状态优先于OMxOLx决定的匹配动作。例如:当OC7匹配后,当某个

    OC7Mn=1,则内部逻辑将C7Dn的值送到相应引脚,若OC7Mn=0,则按照OMxOLx决定

    动作。

     

    注意:有些标志位是要软件清零的,并且是写一清零啲。

     

    ATD

     

    16通道,8- 10- 12-bits可选。S12ATD模块为逐次逼近型(us级别)

    1、有5个那个ATDCTLx  (ATD控制寄存器)0-屏蔽通道;1-分辨率、外部触发源;2-外触发的方

    (上升沿啊、电平啊 什么的)3-单次转换序列长度;4-采样时间、时钟;5-选通道

    2、注意reset后,默认4个转换长度(截图)

    3、外触发就是说通过外部event来触发转换序列的开始:以ETRIGSELETRIGCH[0:3]来选择是用ETRIG[0:3]呢或者用AN[0:15]来当做外部触发的引脚

    4、标志位SCAN:连续转换序列,即转换一次呢还是多次紧接着来转换;

     MULT:0-单个通道转换(由SCCACBCCCD来决定是哪个) 1--多通道转换(同样SCCACBCCCD来决定是从哪一个开始)

    5、内有一个Compare比较功能:把Channel x探测到的值 ATDDRx中预存的值 通过ATDCMPHT(符合寄存器,即大于还是小于)来对比,若正确True则以CCFx来标志。

    6ATDDRx中结果的FormatDJM决定,DJM=0时则为左对齐,为 1 时则为右对齐。

    这点在read这个寄存器的值或者在写入compare值时要分外注意。

     

     

     

    PWM

     

    8个通道,可编程周期、占空比、4个可选时钟(ABSASB),可选左对齐或中心对齐

     

    1、选择时钟:

    PWMCLK分配每个通道的时钟

    PWMPRCLK 时钟预分频:其实是对总线时钟进行预分频来得到Clock AB

    PWMSCLAPWMSCLB则是用来分频产生更精确时钟。如Clock SA=Clock A/2*PWMSCLA

    2、选择极性

    PWMPOL:对通道进行极性控制,如 PWMPOL_PPOL0=1 则通道0在周期开始时先输出为高电平,当计数器等于占空比的值时,则输出为低电平。

    Polarity=0: Duty Cycle=[(PWMPERx-PWMDTYx)/PWMPERx]*100%

    Polarity=1: Duty Cycle=[PWMDTYx/PWMPERx]*100%

    3、选择对齐方式、级联方式

    PWMCAE 数据格式对齐配置,0-左对齐,1-中心对齐

    截图(如图告诉你什么是左对齐,什么是中心对齐)

     

     

    PWMCTL 可使两个8位连接为16位,其中变为16位后,以低位(Low Order)通道做输出或决定输出,比如CON67置位后,注意是以7为低位。

    4、设置周期、占空比

    PWMPERxPWMDTYxPWMCNTx分别为周期、占空比、计数寄存器。

    5、使能PWM  PWMEx寄存

     

     

     

    SCI

     

    复位后,波特率发生器是不工作的 SBR012=0 ;并且在写入SCIBDH后,必须补写SCIBDL 否则不工作。公式为:

     

    数据位若果为9bits,(即SCICR1控制寄存器中M位为1),应先高位写入,再低位。

    SCISR1中的TDREtransmit date regester empty)置高指示写入新的发送数据,复位为1,当其为1时读取SCISR1,再写SCIDRL便可清零。

    RDRF(receive data register full flag)置高指示可以读取接收完的数据,顺次读取SCISR1SCIDR后会自动清零

    主要应用都是像以前那个串口通信一样,发送---》等空---》再发送;或者是 等置高》接收---》等置高。

    另外附有一个红外调制子模块

    并且有LOOPS 模式(跟平时测试时一样,自己输出,再自己接收处理)    single-wire 模式(以TXDIR决定是TXD pin 做输入定输出,应该可以用来弄那个DS18B20,下次试一试)

     

     

    PLL的作用:

     

     

    公式:fvcofpllfbus 调节每一个参数时,都有想应该一个寄存器,而寄存器中有一个频率锁相范围(参数的调节后不能超过这个范围,否则不稳定)通常调好后,要检查CRGFLG中的LOCK标志位(如图)

    0-VCOCLK is not within the desired tolerance of the target freguency

    1-opposite

     

    CLKSEL时钟选择寄存器:决定或配置各模式下的时钟工作或stop情况。使用时要置高PLLSEL

     

    另外PLLCTL寄存器中的PLLON位置高来开启PLL工作电路

    引用龙丘的程序说明

    void SetBusCLK_16M(void)

    {  

        CLKSEL=0X00;                              // disengage PLL to system

        PLLCTL_PLLON=1;                      // turn on PLL

        SYNR=0x00 | 0x01;          // VCOFRQ[7:6];SYNDIV[5:0]

                            // fVCO= 2*fOSC*(SYNDIV + 1)/(REFDIV + 1)

                            // fPLL= fVCO/(2 × POSTDIV)

                            // fBUS= fPLL/2

                            // VCOCLK Frequency Ranges  VCOFRQ[7:6]

                            // 32MHz <= fVCO <= 48MHz    00

                            // 48MHz <  fVCO <= 80MHz    01

                            // Reserved                  10

                            // 80MHz <  fVCO <= 120MHz   11                                

        REFDV=0x80 | 0x01;  // REFFRQ[7:6];REFDIV[5:0]

                            // fREF=fOSC/(REFDIV + 1)

                            // REFCLK Frequency Ranges  REFFRQ[7:6]

                            // 1MHz <= fREF <=  2MHz       00

                            // 2MHz <  fREF <=  6MHz       01

                            // 6MHz <  fREF <= 12MHz       10

                            // fREF >  12MHz               11                        

                            // pllclock=2*osc*(1+SYNR)/(1+REFDV)=32MHz;

        POSTDIV=0x00;       // 4:0, fPLL= fVCO/(2xPOSTDIV)

                            // If POSTDIV = $00 then fPLL is identical to fVCO (divide by one).

        _asm(nop);          // BUS CLOCK=16M

        _asm(nop);

        while(!(CRGFLG_LOCK==1));     //when pll is steady ,then use it;

        CLKSEL_PLLSEL =1;                   //engage PLL to system;

    }

     

     

     

    中断的编写:

    在头文件中可以查找到:

    /**************** interrupt vector numbers ****************/

    #define VectorNumber_Vsi                119

    #define VectorNumber_Vsyscall           118

     

    #define VectorNumber_Vatd0compare       96

     

    #define VectorNumber_Vpit3              69

    #define VectorNumber_Vpit2              68

    #define VectorNumber_Vpit1              67

    #define VectorNumber_Vpit0              66

    #define VectorNumber_Vhti               65

    #define VectorNumber_Vapi               64

    #define VectorNumber_Vlvi               63

     

    #define VectorNumber_Vpwmesdn           57

    #define VectorNumber_Vportp             56

     

    #define VectorNumber_Vcan0tx            39

    #define VectorNumber_Vcan0rx            38

    #define VectorNumber_Vcan0err           37

    #define VectorNumber_Vcan0wkup          36

    #define VectorNumber_Vflash             35

    #define VectorNumber_Vflashfd           34

     

    #define VectorNumber_Vcrgscm            29

    #define VectorNumber_Vcrgplllck         28

     

    #define VectorNumber_Vporth             25

    #define VectorNumber_Vportj             24

     

    #define VectorNumber_Vatd0              22

    #define VectorNumber_Vsci1              21

    #define VectorNumber_Vsci0              20

    #define VectorNumber_Vspi0              19

    #define VectorNumber_Vtimpaie           18

    #define VectorNumber_Vtimpaaovf         17

    #define VectorNumber_Vtimovf            16

    #define VectorNumber_Vtimch7            15        

    #define VectorNumber_Vtimch6            14        

    #define VectorNumber_Vtimch5            13        

    #define VectorNumber_Vtimch4            12        

    #define VectorNumber_Vtimch3            11        

    #define VectorNumber_Vtimch2            10        

    #define VectorNumber_Vtimch1            9 

    #define VectorNumber_Vtimch0            8

    #define VectorNumber_Vrti               7   

    #define VectorNumber_Virq               6  

    #define VectorNumber_Vxirq              5   

    #define VectorNumber_Vswi               4 

    #define VectorNumber_Vtrap              3  

    #define VectorNumber_Vcop               2 

    #define VectorNumber_Vclkmon            1 

    #define VectorNumber_Vreset             0  

    其他的为保留中断位。。。。。。。。。。。。。

     

     

    要点一:

    因为中断矢量只有16位,所以无法在分页地址中寻址。因此,中断函数必须放入非分页地址。在程序文件中要将中断函数放入非分页地址,用这样的格式:

    #pragma CODE_SEG NON_BANKED

    。。。中断函数。。。

    #pragma CODE_SEG __NEAR_SEG NON_BANKED

    所以说我们的中断服务例程必须被“#pragma CODE_SEG NON_BANKED”和“#pragma CODE_SEG DEFAULT”包围起来。

     

    要点二:

    中断的服务程序名的写法一般有以下几种

    1.interrupt关键字+中断向量号+自己的isr函数

    2.interrupt关键字+isr函数(isrprmVECTOR ADDRESS 映射)

    3.#pragma TRAP_PROC声明(isrprmVECTOR ADDRESS 映射)

     

    #pragma TRAP_PROC 仅对紧跟着它的函数有效,通知编译器位于它下面的函数是中断函数,其返回指令是RTI,而不是RET,因此每个中断函数前面都必需有这个预处理。在PRM文件中定义中断矢量地址:

     

    VECTOR ADDRESS 0xFFXX My_ISR  加在PRM文件的最后就可以了。

     

     

     

     

     

     

    最新回复(0)