找回密码
 立即注册
楼主: wpppmlah

【实验箱已收到】wpppmlah的课程打卡23-08

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-5 17:12:11 | 显示全部楼层
2023/09/05 何老师 C语言课程打卡记录


当使用指向const对象的指针时,可以在指针定义中排除 const类型限定符,例如:
const unsigned char mask[]={0x01, 0x02, 0x04, 0x08);
const unsigned char *cp=mask;
unsigned char *p=mask;        // 与cp效果相同
*p=' a,;        〃这里没效果,不会导致警告或错误
*cp=,a'》;        〃这会导致错误
从上面可知,可以将常数对象mask的地址分配给非常数的指针p,然后使用该 指针更改常数对象。在这种情况下,编译器会生成代码写入常数对象。该代码的 效果未定义,可能或无法按预期工作
不能使用const指号供更改它指向的常数对象。如果这样做,将导致编译器错误


截图202309051429187924.jpg

截图202309051432033351.jpg


■该程序使用两个变量(reg1和reg2)访问硬件寄存器
■在大多数情况下,编译器将reg1加载到寄存器中,并且不会在循环迭代之 间重新读取它(即使硬件寄存器可能正在更改)
■此外,对reg2的三个赋值可以简单的优化为最终的赋值(前两个赋值不生 成代码)。这些影响是由优化器造成的,而不是编译器生成的错误
■事实上,这些是编译器应该进行的优化类型。然而,在这种情况下,它们 肯定是不可取的

截图202309051440026191.jpg

截图202309051503221099.jpg 截图202309051520346160.jpg

截图202309051522223480.jpg



【例8-6】数组元素存储和运算的C语言代码
void main()
{
const char code table[]={1,2,4,8};
volatile char i=0,sum=0;
for(i=0;i<4;i++)
sum+=table;
}



■该C语言代码对应的反汇编代码
1: void main()
2:{
3: const char code table[]={1,2,4,8};
4:        volatile char i=0,sum=0;
0XFF0003 E4           CLR       A
0XFF0004 7AB30008 MOV        j(0x0008),R11
0XFF0008 7AB30009 MOV        sum(0x0009),R11
5:        for(i=0;i<4;i++)        }
0xFF000C 8021
SJMP C:0x002F

第二部分

C语言支持许多可以应用于程序变量的存储类
■存储类用于定义变量和函数的范围和生存周期,这些存储类关键字包括:
■        auto
■        register
■        static
■      extern




auto存储类是本地变量默认的存储类
■其格式如下:
auto data-type name <[>=value<]>
其中
■        data-type为变量的数据类型
■        name是变量的名字
■        value是分配给变量的值
需要注意,存储类auto只能在函数定义内使用



register存储类定义了应该保存在一个或多个寄存器中而 不是RAM中的局部变量
■其格式如下:
register data-type name <[>=value<]>;
其中
■        data-type为变量的数据类型
■        name为变量的名字
■        value为分配给变量的值
■通常,C251编译器忽略register存储类。如果有可能,所有变 量都保存在寄存器中
注:存储类register只能在函数定义内使用

static 存储类限制变量的范围并修改局部变量的生存期

■其格式如下:
static data-type name <[>=value<]>;
其中
■        data-type为变量的数据类型
■        name务变量的名字
■        value是分配给变量的值
■使用static在函数外部声明变量时,无法在声明变量的源文件外部访问该变量
■当使用static在函数内部声明变量时,该变量在启动时就被初始化(与其他全局变量一样),并且在调用该函数时保留其值
■在进入函数时它不会被重新初始化



extern存储类声明在另一个源模块中定义的全局变量
■其格式如下:
extern  data-name  name;
其中
■        data-type为变量的数据类型
■        name为变量的名字
■当使用extern声明变量时,无法初始化该变量,这是因为它已经在定义的位置初始化了



【例8-7】存储类用法的C语言描述
     在extern.c文件中定义变量
     short int a=3000,b=-2000;
     在main.c文件中调用外部变量
     #include "math.h"
     extern short int a,b;
    void main()
    {
      volatile long int c;
      c=a*b;
    }


下一节,静态变量 在整个程序运行中状态和含义。
static:
int i=0;
int cal(int x)
{
    static int y=0;
    y=x-y-i;
  return y;
}

void main()
{
   int j=1000;
   i=cal(j);
    i=cal(j);
   i=cal(j);
}


变量可以使用_at关键字定位在绝对存储器的位置
■其格式为:
type[memory_type] variable_name   _at_  const_expr;
其中
■        type为变量的类型
■        memory_type为变量的存储器类型。如果在声明中排除该项,则使用默 认存储器通
■        variable_name为变量的名字
■        const_expr为必须计算为绝时常数值的表达式。表达式的结果是定位变 量的地址



随在_at_关键字后面的绝对地址必须符合变量存储空间的 物理边界,
■对于xdata和code存储器类型,该表达式解释为相对于存储器类 型的基地址的偏移量
■        C251编译器为xdata和code变量生成OFFS重定位类型
■对于其他存储器类型,_at_表达式表示STC32G系列单片机中的 绝对存储器位置
■        C251编译器检查地址范围是否有效

截图202309051618499925.jpg

截图202309051619536930.jpg

第三个内容 :指针 ******p

C251编译器支持使用*字符声明变量指针
■ C251编译器可用于执行标准C中可用的所有操作



可以在指针声明中使用存储器类型来定义指针的大小
■没有显式存储器类型的指针称为通用指针
■具有显式存储器类型的指针称为存储器特定指针
■特定于存储器的指针为每个变量访问生成更高效的代码

截图202309051628448463.jpg

截图202309051633483222.jpg


■指向data或idata对象的指针可以使用near存储器类型声明
■因为near指针也可以访问data或idata存储器
■在TINY和XTINY存储器模型中,默认指针大小为16位,指针的 默认存储器类型为near*
■要访问0x010000以上的存储器区域,必须在指针声明中指定存储器类型 为far *或huge *
■使用far或者huge指针,可以寻址near、data或idata对象。
不同之处在于
■        far或huge指针访问使用@DPk指令,然而near指针使用更高效的 @WRj指令
■        far或huge对象不能用near指针寻址


下面给出一些使用例子:
■        char near *px;
■声明一个指针,该指针引用near存储器类型中char类型的对象。指针本 身保存在默认存储器类型中(取决于使用的存储器模型).大小为两个字
■        char near *data pdx;
■该声明与先前的声明相对应,只是指针本身被明确地放置到数据存储器 (data)中,而与使用中地存储器模型无关
■        int (* xdata fp) (void);
■该声明定义了函数指针,该函数指针被显式放置到xdata存储器类型中, 而与使用地存储器模型无关。所寻址的函数的类型为void func (void)



struct ptime{
char hour;
char min;
char sec;
struct time near *pxtime;
};
■除了其他元素之外,该结构还包含指向另一个结构的指针pxtime,该结 构必须位于near存储器类型中。指针pxtime的大小为两个字节


■        struct time far *ptime;
■该声明定义了一个指针,该指针保存在默认的存储器类型中,并引用位于 far存储器类型中的struct time。指针ptime需要四个字节
■        ptime- > pxtime- > hour = 12;
■使用前面的两个声明。指针pxtime是从结构间接加载的。它指向struct time,位于near存储器类型。将值12分配给该结构的成员hour



C251编译器可以转换指针的存储器类型
■指针转换可以由使用建型强制转换的显式程序代码强制执行,也可以由编译器强制执行
■通用指针与TINY或XTINY存储器模型的near *指针定义相同。对于所有 其他存储器模型,通用指针与far *指针定义相同


当存储器特定指针作为参数传递给需要通用指针的函数时,
C251编译器将存储器特定指针转换为通用指针
■ C251运行时库函数(如printf、sprintf和gets)的情况就是如 此,这些函数使用通用指针作为参数
■例如:


extern int printf (void *format,...);
extern int myfunc (void near *p, int data *dq);
int data *dp;
const char near *fmt = "value = %d | %04XH\nM;
void debug print (void) (
printf (fmt, *dp);        // 转换fmt
myfunc (fmt, nx);        // 没有转换
}


■在对printf的调用中,表示2字节near指针的参数fmt被自动转 换成强对为通用指针
■这样做是因为printf的原型需要一个通用指针作为第一个参数。根据存储 器模型,通用指针的大小为2个字节或4个字节
注:在TINY或XTINY存储器模型中,无法使用标准C251运行时库函数访问 0x010000以上的存储器位置。因此,printf的格式字符串必须声明为const char near.如果将格式字符串声明为char code (如C51程序中所做的那样), 则printf仅适用于SMALL. XSMALL或LARGE存储器模型
■由于将地址空间看作是线性实体,因此指针转换主要通过扩展或截断指针的高位部分完成

截图202309051655299534.jpg

截图202309051656229973.jpg

























































截图202309051503342069.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-6 16:31:05 | 显示全部楼层


2023/09/06 陈桂友教授课程  ADC应用
截图202309061622356143.jpg


内容提纲
具有模拟量输入输出的单片机系统构成
模数转换器的工作原理及性能指标
STC8H8K64U单片机ADC的结构及寄存器


1 具有模拟量输入输出的单片机系统构成

*随着数字电子技术及计算机技术的广泛普及与应用,数字信号的传输 与处理日趋普遍。
*自然形态下的物理量多以模拟量的形式存在的,如温度、湿度、压力、 流量、速度等,实际生产、生活和科学实验中还会遇到化学量、生物 量(包括医学)等。
*从信号工程的角度来看,要进行信号的计算机处理,上述所有的物理 量、化学量和生物量等都需要使用相应的传感器,将其转换成电信号(称之为模拟量)
*将模拟量转换为计算机能够识别处理的数字量,而后再进行信号的传 输、处理、存储、显示和控制。

◊同样,计算机控制外部设备时,如电动调节阀、调速系统等, 需要将计算机输出的数字信号变换为外设能够接受的模拟信号。
◊将模拟量转换成数字量的器件称为模数转换器(Analog toDigital Converter, ADC),也称为A/D转换器或者ADC器件;
◊将数字量转换成模拟量的器件称为数模转换器(Digital toAnalog Converter, DAC),也称为D/A转换器。

截图202309061423053399.jpg

传感器和变送的区别
  传感器是一种把非电量转变成电信号的器件
检测仪表在模拟电子技术条件下,一般包括传感器、检测点取样设备及放大器(进行搞干扰处理及信号传输)
当然还有电源及现场显示部分(可选择)
电信号一般分为连续量、离散量两种实际上还可分成模拟量、开关量、脉冲


模拟信号-般采用4-20m DC的标准信号传输。数字化过程中,常常把传感器 和微处理器及通信网络接口封装在一个器件(称为检测仪表)中,完成信息获 取、处理、传输、存贮等功能。


在自动化系统中经常把检测仪表称为变送器,如湿度变送器、压力变送器等。


一、模数转换器的工作原理
◊根据转换的工作原理不同,模数转换器可以分为计数-比较式、 逐次逼近式和双斜率积分式。



◊计数-比较式模数转换器结构简单,价格便宜,转换速度慢,较 少采用。
◊下面主要介绍逐次逼近式模数转换器的工作原理。

截图202309061438465166.jpg



◊工作过程
♦当模数转换器收到“转换命令”并清除SAR寄存器后,控制电路先设定SAR 中的最高位为“1”,其余位为“0”,此预测函数被送至D/A转换器,转换成 电压Vc。
♦然后将Vc与输入模拟电压Vx在高增益的比较器中进行比较,比较器的的输出 为逻辑0或逻辑1。
•如果Vx>Vc,说明此位置“1”是对的,应予保留(1);


•如果Vx<Vc,说明此位置“1”不合适,应予清除(0) .


♦按该方法继续对次高位进行转换、比较和判断,决定次高位应取“1”还是取 “0”。
♦重复上述过程,直至确定SAR最低位为止。
♦该过程完成后,状态线改变状态,表示已完成一次完整的转换,SAR中的内 容就是与输入的模拟电压对应的二进制数字代码。


二、模数转换器的性能指标
A/D转换器是实现单片机数据采集的常用外围器件。A/D转 换器的品种繁多,性能各异,在设计数据采集系统时,首先碰到 的问题就是如何选择合适的A/D转换器以满足系统设计的要求。
选择A/D转换器需要综合考虑多项因素,如系统技术指标、 成本、功耗、安装等。


1、分辨率
   分辨率是A/D转换器能够分辨最小信号的能力,表示数字量变 化一个相邻数码所需输入模拟电压的变化量。分辨率越高,转换时 对输入模拟信号变化的反应就越灵敏。
   例如,8位A/D转换器能够分辨出满刻度的1/256,若满刻度输 入电压为5V,则该8位A/D转换器能够分辨出输入电压变化的最小值 约为 19.5mV.


2、通道
   有的单芯片内部含有多个ADC模块,可同时实现多路信号的转换;常见的多 路ADC器件只有一个公共的ADC模块,由一个多路转换开关实现分时转换。


3、基准电压
   基准电压有内、外基准和单、双基准之分。



4、转换速率       
转换时间:A/D转换器从启动转换到转换结束,输出稳定的数字量,需要的 一定的转换时间。
转换速率:转换时间的倒数就是每秒钟能完成的转换次数。
A/D转换器的型号不同,转换时间不同。逐次逼近式单片A/D转换器转换时 间的典型值为1.0-200uS- STC8H系列的ADC最快速度:12位ADC为800K (每秒进行 80万次ADC转换,12.5uS/次),10位ADC为500K (每秒进行50万次ADC转换)


5、采样/保持器
采样/保持也称为跟踪/保持(Track/Hold缩写T/H)。
原则上采集直流和变化非常缓慢的模拟信号时可不用采样保持器。
对于其他模拟信号一般都要加采样保持器。如果信号频率不高,A/D转换器的 转换时间短,即使用高速A/D转换器时,也可不用采样/保持器。


6、量程
量程即所能转换的电压范围,如2.5V、5V和10V。


7、满刻度误差
满度输出时对应的输入信号与理想输入信号值之差称为满刻度误差。


8、线性度
实际转换器的转移函数与理想直线的最大偏移称为线性度。


9、数字接口方式
  根据转换的数据输出接口方式,A/D转换器可以分为并行接口和串行接口两种 方式。
并行方式一般在转换后可直接读取数据,具有明显的转换速度优势,但芯片的 引脚比较多;
串行方式所用芯片引脚少,封装小,使用串行器件可以节省I/O资源,但需要 软件处理才能得到所需要的数据。
STC8H8K64U单片机内部集成了一个12位高速A/D转换器,使用单片机集成的ADC时,不存在接口问题。


10、模拟信号类型
通常ADC器件的模拟输入信号都是电压信号。同时根据信号是否过零,还分 成单极性(Unipolar)信号和双极性(Bipolar)信号。


11、电源电压
电源电压有单电源、双电源和不同电压范围之分,如果选用单+5V电源的芯片 则可以使用单片机系统电源。


12、        功耗
一般CMOS工艺的芯片功耗较低,对于电池供电的手持系统对功耗要求比较高 的场合一定要注意功耗指标。
13、        封装
常见的封装有双列直插封装(DIP)和表贴型(SMD)封装。


三STC8H8K64U单片机ADC的结构及寄存器(参考示意图)

截图202309061504096882.jpg


2、与ADC有关的特殊功能寄存器
(1) ADC控制寄存器
截图202309061514089679.jpg

ADC_POWER: ADC电源控制位
0:关闭ADC电源
1:打开ADC电源。
建议进入空闲模式和掉电模式前将ADC电源关闭,以降低功耗(800uA)。
特别注意:
给MCU的内部ADC模块电源打开后,需等待约1ms,等MCU内部的ADC 电源稳定后再让ADC工作。

截图202309061515401080.jpg


ADC_START: ADC转换启动控制位。
写入1后开始ADC转换,转换完成后硬件自动将此位清零。
0:无影响。叩使ADC已经开始转换工作,写0也不会停止A/D转换。
1:开始ADC转换,转换完成后硬件自动将此位清零。
ADC_FLAG: ADC转换结束标志位。
当ADC完成一次转换后,硬件会自动将此位置1,并向CPU提出中断请求。 此标志位必须软件清零。


截图202309061516438463.jpg


ADC_EPWMT:使能PWM实时触发ADC功能。(建议等长ADC检测要用PWM来启动)
ADC_CHS[3:0]: ADC模拟通道选择位
注意:被选择为ADC输入通道的I/O口,必须设置PxMO/PxMl寄存器将I/O 口模式设置为高阻输入模式。
另外,如果MCU进入掉电模式/时钟停振模式后,仍需要使能ADC通道,则 需要设置PxIE寄存器关闭数字输入通道,以防止外部模拟输入信号忽高忽低而产 生额外的功耗。

截图202309061522306706.jpg

截图202309061523029045.jpg

截图202309061523453415.jpg



SPEED[3:0]:设置ADC工作时钟频率。
{ FADC=SYSclk/2/(SPEED+1))

截图202309061525263852.jpg

截图202309061525388496.jpg



当A/D转换完成后,12位的转换结果会自动保存到ADC_RES和 ADC_RESL中。保存结果的数据格式请参考ADC_CFG寄存器中的 RESFMT 设置。

截图202309061526025607.jpg


CSSETUP: ADC通道切换时间控制T(setup)
0:占用1个ADC工作时钟(默认值)
1:占用2个ADC工作时钟


CSHOLD[1:0|: ADC通道选择保持时间控制T(hold)
00 :占用1个ADC工作时钟
01 :占用2个ADC工作时钟(默认值)
10        :占用3个ADC工作时钟
11        :占用4个ADC工作时钟



SMPDUTY[4:0]: ADC模拟信号采样时间控制T(duty) :占用1个ADC工作时钟 00001 :占用2个ADC工作时钟
01010 :占用11个ADC工作时钟(默认值)
11110        :占用31个ADC工作时钟
11111        :占用32个ADC工作时钟
注意:SMPDUTY 一定?不能设置小于01010B

截图202309061535247275.jpg

截图202309061535371682.jpg


ADCETRS[1:0|: ADC外部触发脚ADC——ETR控制位
0x:禁止ETR功能
10:使能ADC_ETR的上升沿触发ADC
11:使能ADC_ETR的下降沿触发ADC
注:使用此功能前,必须打开ADC_CONTR中的ADC电源开关,并设置 好相应的ADC通道


CVTIMESEL[2:0]: ADC自动转换次数选择
Oxx:转换1次
100:转换2次并取平均值
101:转换4次并取平均值
110:转换8次并取平均值
111:转换16次并取平均值
注:当使能ADC自动转换多次功能后,ADC中断标志只会在ADC自动转换 到设置的次数后,才会被置1 (例如:设置CVTIMESEL为101B,即ADC自 动转换4次并取平均值,则ADC中断标志位每完成4次ADC转换才会被置1)

一ADC相关计算公式
截图202309061554411206.jpg


注意:
■        12位ADC的速度不能高于800KHz
■        SMPDUTY的值不能小于10,建议设置为15
■        CSSETUP可使用上电默认值0
■        CHOLD可使用上电默认值1 (ADCTIM建议设置为3FH)


2   ADC转换结果计算公式
截图202309061555053591.jpg

截图202309061555224447.jpg

截图202309061556214462.jpg

截图202309061556404900.jpg



二、ADC的应用
1、编程步骤
■设置相关I/O的工作模式(高阻输入)


■设置ADC内部时序,ADC采样时间建议设村大华(ADCTIM)
■设置ADC时钟(ADCCFG )

■使能 ADC 模块(ADC_CONTR )       
■启动AD转换

■取结果

■清除标志位


二、ADC的应用
2、实例:NTC测温并显示
■读 ADC
■测温度时,使用12位的ADC值,使用对分查找表格来计算,小数点后一 位数是用线性插补来计算


截图202309061600287428.jpg

截图202309061605232822.jpg


























































































































































































































































截图202309061447233544.jpg
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-8 17:12:25 | 显示全部楼层
2023/09/08 下午课程 打卡

仿真,下载再复习。

何宾教授 C语言应用
指针
截图202309081534344106.jpg

通用指针 :没有类型限定的指针,占用四个字节。
截图202309081538268393.jpg

函数

C251编译器为标准C函数声明提供了很多扩展
■这些扩展包括:
■将函数声明为中断过程
■设置寄存器组
■选择存储器模型
■声明可重入函数
■声明外来函数
■程序开发人员可以在函数声明中包含这些扩展或属性(许多可以 进行组合)


参数的传递,返回的参数的底层逻辑!
递归调用函数,重入函数!


使用下面的格式声明函数:
[return type] funcname ([args]) [{small | large}]
[_attribute_ ((attrib spec))]    //可选类型符  可以使用的跟函数有关的属性
[reentrant ]                        //C 语言的关键字,表示 此函数是递归的或可重入
[interrupt n]                        //中断 号
[using y]                            //指定使用  可选寄存器
其中:
■        return_type是从函数返回值的类型。如果没有指定类型,假定为int
■        funcname是函数的名字
■        args是函数的参数列表


■        small显式定义函数使用小(small)存储器模型
■        large显式定义函数使用大(large)存储器模型
■        _attribute_是后跟属性规范的关键字
■        attrib_spec是用双括号括来的属性规范。例如,
■        reentrant指示函数是递归的或可重入的
■        interrupt指示函数是一个中断函数
■      n是中断号
■        using指定函数使用的寄存器组
■        y是寄存器组的编号



函数参数和局部变量保存在存储器模型指定的默认存储器 空间中
■程序开发人员可以通过在函数声明中包含small或large函数属性 来指定用于单个函数的存储器模型
■使用SMALL存储器模型的函数的优点在于本地数据和函数参数保存在 STC32G系列单片机的片上RAM中。因此,数据访问非常高效。内部存储 器是有限的
■有时,small模型不能满足非常大的程序的要求,必须使用其他存储器模 型。对于这种情况,程序开发人员可以声明函数使用不同的存储器模型


■通过在函数声明中指定函数模型属性,可以选择使用两个可能的可重入堆 栈和帧指针中其中一个。在SMALI1模型中堆栈访问比LARGE模型中的更 有效
注:C251版本2或更高版本提供#pragma函数命令。使用该指命令,程序开发 人员可以为一个或多个函数单独指定模型或可重入属性,而无需修改函数声明


寄存器组

在STC32G系列单片机中,DATA存储器的前32个字节 (0x00~0x1F)*被分为4组,每组8个寄存器
■程序以R0~R7的形式访问这些寄存器。寄存器组由程序状态字 PSW的两位选择
■当处理中断或使用实时操作系统时,寄存器组非常有用,因为单片机可以 为任务或中断切换到不同的寄存器组,而不是保存堆栈上的所有8个寄存 器。然后,单片机可以在返回之前将切换到原始组


注:using属性不能用于在寄存器中返回值的函数中。程序开发人员必须格外小 心,确保寄存器组切换位在精心控制的区域进行。否则,可能产生错误的函数结
果。即使使用相同的寄存器组,使用using属性声明的函数也不能返回位值
using属性在中断函数中最有用
■通常为每个中断优先级指定不同的寄存器组
■程序开发人员可以为所有mE中断代码分配一个寄存器组。为高级中断分配
第二个寄存器组和为低级中断分配第三个寄存器组


STC32G系列单片机提供了大量的硬件中断,可用于计数 器、定时器、检测外部事件以及使用串口发送和接收数据 ■ C251编译器支持最多32个中断(0~31)的中断函数! ! ! !
■对于多于32个中断的其他中断,使用STC公司提供的工具进行特殊处理, 本章后续将详细说明


Interrupt属性将值在0~31范围内的整数常数作为参数
■函数原型中不允许使用带有运算符和中断属性的表达式
■ interrupt属性影响函数的目标代码如下:
■当需要时,ACC、B、DPH、DPL、PSW和PSW 1的内容将在函数调用时 保存在堆栈中
■如果未使用using属性指定寄存器组,则中断函数中使用的所有工作寄存 器都将保存在堆栈中
■退出函数之前,将恢复保存在堆栈中的工作寄存器和特殊寄存器
■在使用汇编语言编写ISR时,中断函数的末尾需要使用RETI指令,表示该 中断函数从中断返回


十卞面的规则适用于中断函数,包括:
■无法传递参数 当中断程序中包含任何参数声明时,编译器会发出错误消 息
■中断函数声明不能包含返回值。它们必须声明为void。如果尝试定义中断 函数的返回值,则编译器会发出错误消息。返回类型void应用于所有中断 程序声明。但是编译器会忽略隐含int返回值
■编译器识别对中断函数的直接调用并拒绝它们。使用RETI指令退出中断程 序。RETI恢复PSW1的值并影响STC32G系列单片机的中断系统。不要通 过函数指针间接调用中断函数
■编译器为每个中断函数生成一个中断向量。为向量生成的代码是跳转到中 断函数的开头。通过在C251命令行中使用C251命令NOINTVECTOR, 可以抑制中断向量的生成。在这种情况下,必须从单独的汇编程序模块中


■ -C251编译器允许范围为0~31的中断号
■由于大多数C251库函数都是完全可重入的,因此对调用这些函数没有任 何限制。C251在堆栈中为自动变量使用可重入代码。因此,程序开发人 员可以调用任何使用reentrant属性编译的C251函数,或者在函数执行期 间只使用寄存器
■ C251从不为寄存器访问生成绝对地址。每个C251函数独立于实际使用的 寄存器组。不再需要C51编译器中已知的NOAREGS命令
注:有时,删除using属性并让C251编译器PUSH (入栈)使用的寄存器会更有 效。这也节省了额外寄存器组所需要的数据存储器。程序开发人员可以将使用或 不使用属性生成的代码与C251 CODE命令进行比较


可重入函数可以同时由多个进程共享
■当一个可重入函数正在执行时,另一个进程可以中断执行,然后 开始执行相同的可重入功能
■默认情况下,C251编译器生成静态代码,这意味着函数通常不能递归调 用或以导致可重入的方式调用
■静态代码的优点是函数参数和局部变量保存在固定的存储位置,这允许 STC32G系列单片机快速访问变量
■函数属性reentrant允许程序开发人员声明可重入的函数,因此 可以递归调用


可重入函数可以同时由多个进程共享
■当一个可重入函数正在执行时,另一个进程可以中断执行,然后 开始执行相同的可重入功能
■默认情况下,C251编译器生成静态代码,这意味着函数通常不能递归调 用或以导致可重入的方式调用
■静态代码的优点是函数参数和局部变量保存在固定的存储位置,这允许 STC32G系列单片机快速访问变量
■函数属性reentrant允许程序开发人员声明可重入的函数,因此 可以递归调用


C函数可以传递寄存器和/或固定存储器位置中的参数
■ REGPARMS和NOREGPARMS命令使能/禁止使用寄存器传递 参数
■如果禁止使用寄存器传递参数,或者传递的参数套多而无法装入寄存器, 则在固定存储器位置传递参数
■通常,使用寄存器参数


传递到固定存储器位置的汇编程序例程的参数使用名字 为?function name?BYTE和?function name?BIT保存 传递给函数function name的参数值
■在调用函数之前,位参数被复制到?function_name?BIT段。所有其他参 数都复制到?function name?BYTE段
■即使使用寄存器传递参数,所有参数也会在这些段中分配空间。参数按照 在每个段中声明的顺序保存
■用于参数传递的固定存储器位置可以是存储器类DATA、EDATA或 XDATA,具体取决于所使用的存储器模型


C251编译器使用寄存器R11和R0~R7进行参数传递
■寄存器中最多可以传递9个参数
■所有其他参数都使用固定存储器位置或STC32G系列单片机内的
硬件堆栈传递(取决于函数reentrant/static属性)

截图202309081655367110.jpg 截图202309081656226866.jpg

截图202309081706292922.jpg


■对于传递给C51函数的参数;寄存器R1/R2/R3中返回3字节指 针。大小为[1..8]两结构返回类型返回到寄存器R0~R7中,最后 一个结构元素的LSB始终以R7结尾
■例如,在R5、R6和R7中返回3字节的结构值。大小为5的结构返回到R3、 R4、R5、R6和 R7
■包含超过8个字节的结构在内部memcpy函数的帮助下返回
■目的地址必须在DR12的调用时传递给函数

截图202309081709468022.jpg
























































回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-13 14:17:08 | 显示全部楼层
2023/09/12 何宾教授 32位单片机C语言架构

C语言程序实例








函数的存储类型 small large


函数指针(指向函数所在的地址)




关键字—attribute.允许在声明时指定特殊的属性
.该关键字后面是双括号内的属性规范



alias( "target")
使用该属性为变量和函数指定多个别名
■如果在当前翻译单元中定义了变量或函数,则别名引用将替换为 对变量或函数的引用,别名将与原来的名字一起发出
■如果在当前翻译单元中没有定义变量或函数,则别名弓I用将替换 为对实际变量或函数的引用
■如果将变量或函数定义为static,则用别名替换变量或函数名字
■如果别名被声明为外部,则该变量或函数声明为外部





函数别名:



-aligned(n)
aligned(n)是一个变量和函数属性,用于指定变量、结 构体字段或函数的最小对齐方式
■n以字节为单位指定对齐方式
■ aligned属性优先于命令ORDER
■关键字_at_覆盖对齐属性







noreturn是一个函数属性,用于通知编译器该函数永远 不会返回
■然后编译器可以优化并生成更好的代码
■更重要的是,它有助于避免未初始化变量的虚假警告
■不要假设在调用noreturn函数之前,调用函数保存的寄存器已 恢复
■ noreturn函数的返回类型应该为void
■该属性在C251版本5.51中实现
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-13 15:21:34 | 显示全部楼层
2023/09/13 陈桂友教授
PWM模块的应用:


截图202309131417548854.jpg


时基单元的预分频时钟(CK_PSC)可以由以下资源提供:
(1)        内部时钟(CK_INT)
(2)        外部时钟模式1:外部时钟输入(Tlx)
(3)        外部时钟模式2:外部触发输入ETR
(4)        内部触发输入(ITRx):使用一个PWM的TRGO做为另一个PWM的 预分频时钟。


1、内部时钟源fmaster)
如果同时禁止了时钟/触发模式控制程和外部触发输入(PWMA—SMCR寄存 器的SMS=000, PWMA_ETR寄存器的ECE=.0),贝ijCEN、DIR和UG位是实际 上的控制位,并且只能被软件修改(UG位仍被自动清除)。一旦CEN位被写成 1,预分频器的时钟就由内部时钟提供。

截图202309131422348743.jpg


2、外部时钟源模式1
当PWMA_SMCR寄存器的SMS=111时,,选择外部时钟源模式。通过 PWMA_SMCR寄存器的TS位选择TRGI的信号源。计数器可以在选定输入端的 每个上升沿或下降沿计数。

截图202309131425433633.jpg


要配置向上计数器在TI2输入端的上升沿计数,使用下列步骤:
(1)        配置PWMA_CCMR2寄存器的CC2S=01,通道2输入选择TI2;
(2)        配置PWMA_CCMR2寄存器的IC2F[3:0]位,选择输入滤波器带宽;
(3)        配置PWMA_CCER1寄存器的CC2P=0,选定上升沿极性;
(4)        配置PWMA_SMCR寄存器的SMS=111,配置计数器使用外部时钟模式1 ;
(5)        配置PWMA.SMCR寄存器的TS=110,选定TI2作为输入源;
(6)        设置PWMA.CR1寄存器的CEN=1,启动计数器。

截图202309131435313375.jpg


3、外部时钟源模式2
计数器能够在外部触发输入ETR信号的每一个上升沿或下降沿计数。将PWMA_ETR寄存器的ECE位写1,即可选定此模式。
(PWMA_SMCR寄存器的 SMS=111且PWMA_SMCR寄存器的TS=111时,也可选择此模式)

截图202309131442325149.jpg

截图202309131443269481.jpg


二 捕获/比较通道

PWM1P、PWM2P、PWM3P、PWM4P可以用作输入捕获;捕获只能用P端
PWM1R/PWM1N、PWM2P/PWM2N、PWM3P/PWM3N. PWM4P/PWM4N 可以输出比较。
上述功能可以通过配置捕获/比较通道模式寄存器(PWMA_CCMRi)的CCiS 通道选择位来实现(其中,i=1,2,3,4)。

截图202309131448299586.jpg


截图202309131453163757.jpg

截图202309131454022429.jpg

截图202309131454155273.jpg

截图202309131455123778.jpg


(2)输入捕获模式的工作过程
在输入捕获模式下,当检测到ICi信号上相应的边沿后,计数器的当前 值被锁存到捕获/比较寄存器(PWMA CCRx)中。


当发生捕获事件时,PWMA_SR寄存器中的相应CCilF杭志被置1。
如果PWMA_IER寄存器的CC1IE位被置位,也就是使能了中断,则将 产生中断请求。


如果发生捕获事件时CC1lF标志已经为高,那么PWMA SR2寄存器中 的重复捕获标志CCiOF被置1。写CCiIF=0或读取存储在PWMA_CCRiL寄 存器中的捕获数据都可清除CCilFo写CCiOF=0可清除CCiOFo



1)实现PWM输入信号上升沿时捕获的设置
例如,在TI1输入的上升沿时捕获计数器的值到PWMA_CCR1寄存器 中。设置步骤:
①        选择有效输入端,设置PWMA_CCMR1寄存器中的CC1S=O1,此时通道1被配置 为输入,并且PWMA_CCR1寄存器变为只读。
②        根据输入信号TI1的特点,可通过配置PWMA_CCMR1寄存器中的IC1F位来设置 相应的输入滤波器的滤波时间。假设输入信号在最多5个时钟周期的时间内抖动,须配置 滤波器的带宽长于5个时钟周期,因此,可以连续采样8次,以确认在TI1上一次真实的边 沿变换,即在PWMA_CCMR1寄存器中写入IC1F=OO11,此时,只有连续采样到8个相同 的TI1信号,信号才为有效(采样频率为fMASTER)。


③        选择TI1通道的有效转换边沿,在PWMA_CCER1寄存器中写入 CC1P=0 (上升沿)»
④        配置输入预分频器。在本例中,希望捕获发生在每一个有效的电平 转换时刻,因此,预分频器被禁止(写PWMA_CCMR1寄存器的 IC1PS=OO) o
⑤        设置PWMA_CCER1寄存器的CC1E=1,允许捕获计数器的值到捕 获寄存器中。
⑥        如果需要,通过设置PWMAJER寄存器中的CC1IE位允许相关中断 请求。



2) PWM输入信号测量
该模式是输入捕获模式的一个特例,除下列区别外,操作与输入捕获 模式相同:
•两个ICi信号被映射室同一个TIi输入。
-这两个ICi信号的有效边沿的极性相反。
・其中一个TliFP信号被作为触发输入信号,而触发模式控制器被配置 成复位触发模式。


例如,可以用以下方式测量TI1上输入的PWM信号的周期(PWMA_CCR1寄 存器)和占空比(PWMA_CCR2寄存器)。
①        选择PWMA_CCR1的有效输入:置PWMA_CCMR1寄存器的CC1S=O1 (选中TI1FP1)。
②        选择TI1FP1的有效极性:置CC1P=O (上升沿有效)。
③        选择PWMA_CCR2的有效输入:置PWMA_CCMR2寄存器的CC2S=10 (选中TI1FP2)。
④        选择TI1FP2的有效极性(捕获数据到PWMA_CCR2):置CC2P=1 (下降沿有效)。
⑤        选择有效的触发输入信号:置PWMA_SMCR寄存器中的TS=101 (选择TI1FP1)。
⑥        配置触发模式控制器为复位触发模式:置PWMA_SMCR中的SMS=100o
⑦        使能捕获:置PWMA CCER1寄存器中CC1E=1, CC2E=1。

截图202309131505538806.jpg


截图202309131507422406.jpg

截图202309131508285754.jpg



(2)强制输出模式
在输出模式下,输出比较信号能够直接由软件强制为高或低状态,而 不依赖于输出比较寄存器和计数器间的比较结果。
置PWMA_CCMRi寄存器的OCiM=101,可强制OCiREF信号为高。
置PWMA CCMRi寄存器的OCiM=100,可强制OCiREF信号为低。


(3)输出比较模式
此模式用来控制一个输出波形或者指示一段给定的时间已经达到。
当计数器与捕获/比较寄存器的内容相匹配时,有如下操作:
①        根据不同的输出比较模式,相应的OCi输出信号:
•        OCiM=000时,保持不变
•        OCiM=001时,设置为有效电平
•        OCiM=010时,设置为无效电平
•        OCiM=011 时,翻转
②        设置中断状态寄存器中的标志位(PWMA—SR1寄存器中的CCilF位)。
③        若设置了相应的中断使能位(PWMA—IER寄存器中的CCiIE位),贝I」产生 一个中断。


(4) PWM模式
②向下计数的配置(PWMA_CR1寄存器中的DIR位为1)
在PWM模式1时,当PWMA_CNT>PWMA_CCRi时参考信号OCiREF为低, 否则为高。如果PWMA_CCRi中的比较值大于PWMA_ARR中的自动重装载值, 则OCiREF保持为高。该模式下不能产生占空比为0%的PWM波形。

截图202309131520391214.jpg
该模式是输入捕获模式的一个特例,除下列区别外,操作与输入捕获 模式相同:
•两个ICi信号被映射室同一个TIi输入。
-这两个ICi信号的有效边沿的极性相反。
・其中一个TliFP信号被作为触发输入信号,而触发模式控制器被配置 成复位触发模式。
































































回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-15 10:57:25 | 显示全部楼层
2023/09/15

内嵌汇编程序

程序开发人员在使用C语言编写应用程序代码时,经常会 遇到需要使用汇编语言编写部分代码的情况 ■有些汇编程序在整个软件设计工程中是必须的
■比如:启动引导代码
.而其他地方使用汇编拒言是为了提高整个软件设计工程的运行效 率


在c语言中使用汇编语言的方法包括两种:
■在C语言程序代码中内嵌汇编语言
■ C语言代码程序,调用外部汇编语言编写的程序
■在C源文件中,将汇编代码写在命令中间
#pragma asm
   ......
#pragma endasm


编译器可以从有效的C源文件生成汇编程序源文件(.SRC)
■创建汇编源文件的原因包括:
■使用asm和endasm命令将内联汇编添加到C函数中
■需要手工优化编译器的汇编程序输出。
■程序开发人员正在用汇编代码编写程序,并希望用C语言原型化函数和参


■无论创建.SRC的原因是什么,所需要的步骤始终相同:
■创建C源文件
■添加任何要求的内联汇编指令
■使用SRC命令编译
■重命名.SRC文件,这样不会被原始C源文件的后续编译覆盖(如果需要)
■对创建的汇编程序源文件进行修改
.使用汇编器进行汇编
注:当使用SRC命令时,编译器输出汇编器源文件.SRC,不输出目标(.OBJ)
文件。一旦C源文件转换为汇编器源文件,C符号和源代码级调试就不可用


#include "stdio.h"        // 包含头文件stdio.h
#include "reg251 s.hu // 包含头文件reg251 s.h
/*****声明整型变量C1,位于单片机地址为e:0x0100的存储单元****/ unsigned int edata C1 at_ 0x100;
/*****声明整型变量B1,位于单片机地址为e:0x0102的地址单元****/ unsigned int edata B1 at_ 0x102;
/*****声明整型变量D,位于单片机地址为e:0x0200的地址单元****/ unsigned int edata D1 at 0x200;
/*****声明整型变量e,位于单片机地址为e:0x0202的地址单元*****/ unsigned int edata e _at_ 0x202;



下面的文件包含低层流I/O程序
■使用kiVision IDE时,只需要将修改后的版本添加到工程中即可
C源文件        功能
PUTCHAR.C 有输出字符的所有流程序使用。程序开发人员可以根据自己的硬件 (例如LCD或LED显示器)修改该程序。默认是通过串口输出字符。 XON/XOFF协议用于流控制。换行符("\n")转换为回车符/换行 符序列("\r\n” )
GETKEY.C        由输入字符的所有流程序使用。程序开发人员可以根据自己的硬件 (例如矩阵键盘)修改该程序。默认是通过串口读取字符。不执行 数据转换


截图202309151035213822.jpg



-calloc
该函数为具有num元素的数组分配存储器,数组中的每 个元素占用len字节并初始化为0。分配的存储器字节总数
为 num * len
■该函数的原型为:
     #include <stdlib.h>
     *calloc (num, len);
其中
■ num为条目的个数,len为每个条目的长度
■该函数返回一个执行已分配存储器的指针
■如果无法满足存储器分配请求,则返回一个空指针

free函数将存储块返回到存储池中。参数p指向先前用calloc、malloc或realloc函数分配的存储器块


■该函数的原型为:
#include <stdlib.h>
void free (void xdata *p);
其中
   ■ *p指向要释放的块
■ 一旦该函数将其返回到存储器池,该块就可以用于后续分配
   ■如果P是空指针,则忽略它


-init_mempooy
lnit_mempool函数初始化存储器管理例程,并且提供存储池的起始地址和大小
■该函数的原型为:
#include <stdlib.h>
void init mempool (void xdata *p, unsigned int size);
■其中
■        p参数指向xdata中使用calloc、free、malloc和realloc库函数管理的存 储区域
■        size参数指定用于存储池的字节数


注:在调用任何其他存储管理函数(calloc、free、malloc、realloc)之前, 程序必须调用init_mempool函数来初始化存储器管理例程,并提供存储池的起
始地址和大小。在程序开始时,只调用一次init_mempol函数


-malloc
该函数从长度为size大小的存储池中分配存储块
■该函数的原型为:
#include <stdlib.h>
void xdata *malloc (unsigned int size);
■其中
■ size为要分配块的大小

例子::
截图202309151049078135.jpg

教程的结尾——实验箱例子

--按键扫描与显示
本节将使用C语言编写代码,识别STC32G系列单片机硬 件开发平台上的按键,并在七段数码管上以从左到右的形 式,记录按键的顺序
■比如,第一次按键“T'时,在七段数码管上显示1;在第二次按 键“2”时,在七段数码管上显示12;在第三次按键"4"时, 在七段数码管上显示124
■由于STC系列单片机硬件开发平台上最多有8个七段数码管,因 此可以最多显示当前按键以前8次的按键,按键以其所对应的数 字标识














































回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-9-25 15:37:15 | 显示全部楼层
20230925、陈教授 DMA应用。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-12-18 17:12:05 | 显示全部楼层
20231218 何教授 CAN的应用 12月20继续
1.png

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:510
  • 最近打卡:2025-05-06 08:17:28

15

主题

154

回帖

424

积分

中级会员

积分
424
发表于 2023-12-20 22:00:04 | 显示全部楼层
2023/12/20 何教授 CAN课程打卡

can 打卡1.png

can 打卡2.png

can 打卡3.png

回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-6 18:01 , Processed in 0.139204 second(s), 94 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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