- 打卡等级:以坛为家I
- 打卡总天数:217
- 最近打卡:2024-11-15 09:12:27
荣誉版主
- 积分
- 2790
|
本帖最后由 gentleman 于 2023-7-16 09:38 编辑
大学就学过stc89的开发,看到stc很亲切。现在都推出32位的芯片了!!!赶快学习一下。
学习计划:每天4-5节课(差不多一节大课,根据实际掌握情况调整)。
学到第四课才发现有些课是分上下的 ,计划打乱了。
-----------------------------------目前完成了15课的学习,本贴停更,后续更新另开新帖,试验箱在那里领 ,好多程序等待验证--------------
第一课:认识单片机
这节课内容相对简单。
1.介绍了一下单片机的定义
2.简单介绍了stc的功能和用途。
功能:读取电压,输出电平,计时,计数,等有规律可循的应用。
用途:基本啥都能干,功能很多 。
3.常见问题。
介绍了一下常见的问题。学习门槛低,30也能学,比stm32容易,应用广泛。能做项目评估算入门。小学生也能学( ),上班也能学。
4.学习建议
平心静气(学啥都得这样 )。
多动手做。
举一反三。
看官网,看手册。
逛论坛。
尝试做项目,做竞赛题。
疑问:单片机和FPGA有哪些区别,百度到fpga的定义挺难懂得。学了单片机还要学fpga吗。单片机是否能替代fpga。
第二课:认识硬件
这节课介绍了开发板上的硬件外设(秀肌肉)。
硬件外设
1 红外发射 - 遥控器用的。
2 红外接收 - 也是遥控器用的。
3 电压比较 - 没太懂,大概是给比较器用的?后面会讲。
4 数码管 - 电磁炉,电饭锅之类的会用。
5 万能板 - 拓展用,拓展一些芯片,和中间单片机引出的引脚飞线使用。
6 ntc - 测量温度 (模拟)
7 18b20 - 测量温度 (数字)需采样,没有模拟的快
8 ADC按键 - 1个io16个按键,节省io,adc不是射手。
9 基准电压 - 也是给比较器的。
10 PWM 模拟DAC
-数模转换。可以实现正旋波等。
11 24c02 - 常用的i2c存储器,掉电存储。单片机被玩坏了数据也在。
12 矩阵键盘 - 密码锁用的很多。
13 独立按键 - 1个io1个按键,用与制作定时炸弹。
14 lcd接口 - 可以接那个汉显的lcd屏。
16 led - 灯不亮就不要写程序啦。
17 usb - 这个好像没讲。回头我在翻一下视频。
18 232 - 上古接口,现在pc都看不到了,需要usb转接线。
19 flash扩展
- 可以存放数据。
20 测试接口
- 用不上,要买link,课程不涉及。
21 蜂鸣器
-“全损音质播放器” 常用于提示。
22 led灯 - 流水灯制作。
单片机1.9v-5.5v供电;
128k的flash是存程序的;
ram是草稿纸 放1+1=2 其中的2 的,断电会消失。
作业:板子能做啥。
定时炸弹,音乐播放器。。。 时钟,温度计,掌机游戏机(这个好像有点困难)。
第三课:开发环境搭建和程序下载
1.stc-isp下载
https://stcai.com/gjrj 网址下载。
2.手册下载
stc-isp工具顶部菜单 资料下载 - 手册下载 - 找到stc32系列。
也可以在官网下载。
3.4.pdf阅读器
这个没啥说的,我自己用的苏门答腊pdf 。
记得擅用书签,搜索等功能。
5.c251环境搭建
根据手册上的链接下载c351xxx.exe,一路next就行。
6.程序包下载
stc-isp顶部菜单 资料下载-软件库函数-stc32G库函数
7.编译
stc-isp中添加型号和头文件到keil中
打开下载好的stc32g库函数中的工程文件(.uvproj),这里以跑马灯为例。
点击keil左上的编译 链接 按钮 完成编译,如果编译成功,下方会出现0 errors。
编译成功
8.下载
装好驱动。
选好芯片和端口
通过usb接口下载。
按住p3^2按钮,再按电源按钮,最后再松开p3^2按钮。
点击下载,完成下载。
目前我手上没有实验箱,此处未实际操作。
第四课 上:建立工程点亮第一颗LED上
1.点亮led原理
GPIO 可以通过软件读取其输入电平或控制他输出高低电平。
GPIO----发光二极管 -----限流电阻 ----- 5v (注意二极管方向)
此时GPIO 输出低电平,发光二级管就会被点亮。
类似的还有发光二极管负端接地,GPIO 输出高电平。
2.新建Keil项目
打开keil
点击顶部菜单project- new uvision project,在弹出的对话框输入你的工程名字 0.1DEMO
选择STC MCU 数据库,选择stc32g 单片机
点击file-new 新建 文件
点击file-save 保存文件 文件名 Demo.c
3.写代码 点灯仪式
点灯代码
sbit P00 = P0^0; //这个是定义io引脚
P00 = 0 //输出低电平
sfr 作用 告诉单片机 P0 就是0x80 ,我们可以不使用0x80了。
PXMX 是配置io用的 设置为0x00 是指准双向口。
while是循环。
第四课 下:建立工程点亮第一颗LED下,USB-CDC/虚拟串口,不停电下载,高手必须懂
这节课主要讲不停电下载。
这部分仍旧未通过实际操作。
在stc-isp中选择上图中的选型卡,勾选所有对号。
修改代码,添加stc_usb_hid.LIB库
新建3个变量,将char* USER_STCISPCMD 的值设为自定义的命令 默认为@STCISP#
在main 函数中 添加usb_init() 初始化函数 ,注意不要添加到循环中
打开中断 EA=1;
复制例程中的sys_init()函数到本工程中,并在main函数中调用。
进行下载应该就可以实现了。
课上还介绍了另一种USB-CDC/串口模式。
同样参考例程进行修改。更换相对应的库函数
第五课 C语言运算符和进制数入门
这里上下集是一同看完的,就放到一起写了。由于本人对c语言比较熟悉,所以这部分内容看起来很轻松。
1.1 printf函数
打印函数,在单片机中printf 是将内容打印在串口(usb)中输出。
在主循环中添加上述代码,用于判断 usb是否链接成功, 如果usb 接受到字符,则执行if内部的语句
在if条件语句中添加 打印函数
printf("hello world"); 注意一定要用全角符号,半角符号会报错;
打印函数中可以添加格式字符,常见的格式字符有%d 整形 %f 浮点 %lf 双浮点 %o 8进制 %x 16进制 %c字符 %s字符串
也可添加标志 n.m - 空格 #
常见的转义字符 \r\n windows中的换行符 。
例 printf("温度:%.2f \r\n",15,8);
stc-isp中得到的输出就是 《温度:15.80》。
打印函数在单片机中实际上是以ascii码进行传输的,课程中也给出了ascii码表,在stc-isp中可以查看接收到的ascii (hex)数据。
1.2 数的进制
这部分就是数学知识了,几进制就是逢几进一。
需要掌握之间的换算,pc的计算器调成程序员型可以较快的进行换算。
需要注意的是16进制可以给整组的io赋值使用。
比如 P0=0xff;
就是将整组P0口8个io都改为高电平输出。
16进制也常用与寄存器的赋值。
1.3 c的常用运算符
算数运算符:主要是加减乘除 ,取余,自增自减
就是基本的常用的数学运算。
位运算符:移位 按位与/或 取反
放到二进制中就很好理解了,左移,右移,就是将每一位进行移动,空的补0.
例:1101 0011 << 2 = 11 0100 1100;
按位与/或 就是将对应的位相与/或;
例:1000 0001 & 1000 0000 = 1000 0000;
1000 0001 & 1000 0000 = 1000 0001;
取反就是将所有位取反;
!1000 0000 = 0111 1111;
赋值运算符:后面再讲。
1.4 数据的基本类型
常见的数据类型 bit位 char字符 int整形 float浮点
以及再这些基础上 加上long short signed unsigned 变成 长 短 有符号 无符号的数据类型。
还有sbit sfr sfr_16 这几个好像只在单片机中见到过。
记住每个数据类型的大小,比如bit 只有1位。char 8位
这节课的内容都可以通过printf 打印函数进行验证。让单片机做运算,再将其打印出来;
例:printf("%d",1+1);
printf("%.2f",3.5*5.6);
第六课 LED闪烁和花式点灯
以后上下集都会放到一起记载。
1.基于Delay实现LED的闪烁
1s=1000ms = 1000 000 us
定义时钟频率为24M define 是c的宏定义
#define MAIN_Fosc 24000000UL
定义延时函数
void delay_ms(u16 ms)
{
u16 i; //这是typedef 的头文件里定义过
do
{
i = MAIN_Fosc /6000;
while(--i);
}
while(--ms);
}
do while 是c 的一种循环语句
do while
--ms 就是 ms=ms-1;
--ms -- 在前是先运算在输出
ms-- -- 在后面是先输出在运算;可以使用printf 验证一下;
在主函数循环中调用延时函数
点灯 延时 关灯 延时
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500);
在加一个io可以做汽车的警示灯。
这个delay 使用方便 但弊端是原地踏步
2.函数的使用
函数定义
返回值 函数名 (参数)
{
功能;
}
返回值可以是void 函数名不能是关键词 参数是类型 名称 逗号隔开;
例(加法函数):
int add (int parm1, int parm2)
{
return parm1+parm2;
}
函数声明
返回值 函数名称(参数)
例:
int add (int parm1, int parm2);
函数调用
函数名称(参数)
例:
add(1+2);
3.新建文件使用模块化编程
新建xxx.c 和xxx.h
xxx.h中:
#ifndef __XXX_H_
#define __XXX_H_
调用头文件
函数声明
#endif
xxx.c中:
#include “xxx.h”
函数定义
例:
math.h
#ifndef __MATH_H_
#define __MATH_H_
int add(int int);
#endif
math.c
#include "math.h"
int add (int parm1, int parm2)
{
return parm1+parm2;
}
这个模块课添加很多函数 比如减法 乘法 除法 等
4.课后练习 :3短3长3短(。。。———。。。)
在主循环中添加
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500);
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500);
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500); //3短
P40 = 0;
delay_ms(1000);
P40 = 1;
delay_ms(1000);
P40 = 0;
delay_ms(1000);
P40 = 1;
delay_ms(1000);
P40 = 0;
delay_ms(1000);
P40 = 1;
delay_ms(1000); //3长
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500);
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500);
P40 = 0;
delay_ms(500);
P40 = 1;
delay_ms(500); //3短
第七课 按键点灯
1.按键的原理
1—。/。—2
按下12导通 不按12 闭合
常见用法:
sys-vcc
|
io - 电阻 - - 按键 - gnd
按键有抖动5-10ms
2.按键的代码
if(key == 0)
{
delay_ms(10);
if(key == 0)
{
P60 = !P60; //点灯取反
while(key == 0);
}
}
if基本的c条件语句
key 使用宏定义#define (这里为啥不直接sbit呢)
按键按下执行的动作
可以使用<< 移位来实现 有趣的效果
3.按键的应用
点击点灯,松开灭灯;
点击灭灯,松开点灯; 这两个直接赋值就行
按下一次, 改变一次; 这个取反
按下一次,左走一个; 这个移位
4.数组
定义 类型[长度] = {值}
使用 名称[索引] = 值;
例: int a[2] = {0, 1, 2}
a[1] = 8;
课堂上是使用数组存储整租io口状态,很好用。
使用时便利数组
课后练习:按下按键,切换led输出不同状态
u8 ledStatue = 0x00;
if(key == 0)
{
delay_ms(10);
if(key == 0)
{
ledStatue++;
P6 = ledStatue;
while(key == 0);
}
}
应该是这个效果吧,每点一次灯的状态都不同,还是说一定要用移位来实现,感觉题目不是很清晰。
第八课 蜂鸣器的应用
1.认识蜂鸣器
分有源和无源的,有缘的略贵,因为有震荡源,有黑胶,通电就叫。
2.控制原理
buzzer
P54 高关闭 P54 低开启
自己的尝试:
#define buzzer P54
if(key == 0)
{
delay_ms(10);
if(key == 0)
{
buzzer = !buzzer //点击按键蜂鸣器开,再点关。
while(key == 0);
}
}
和老师写的不能说极其相似,只能说一模一样。
3.蜂鸣器实战应用
这里代码好多,不想抄了,是对之前所学知识的一个整合应用。
简单说就是加了个状态指示 变量 用于标记开关机状态
关机状态下 可以开机 蜂鸣器响
开机状态下 可以关机,点击按键k2 切换led
这里led 的移位没太懂,为啥要-1 ,移位后-1不是相当与没有移位吗,等手上有板子再验证一下,看一下不-1是什么效果。
作业 :
#define key3 P36
u8 working = 0;
if(key3 == 0)
{
delay_ms(10);
if(key3 == 0)
{
working = !working;
while(key3 == 0);
}
}
if(working)
{
led = 0;
delay_ms(200);
led = 1;
delay_ms(200);
}
在功能切换那里也要加if 判断 working 的状态。 working == 0 时才可切换。
u8 老师改成了bit 节省flash空间。
闪灯那里老师改成了关闭整组io口,只关闭1个不可以吗。等手上有板子在试试
第九课 数码管的静态使用
1.认识数码管
开发板上有2个4位数码管
长啥样的都有,内部有led
本质还是点灯,和点亮led相同
8字的里面有8个灯abcdefg dp,分共阳极 和共阴极
共阳的给低电平 共阴的给高电平
4位的abcdefg dp 是连在一起的
2.控制原理
C0 F9 A4 B0 99 92 82 F8 80 90
对应 0 1 2 3 4 5 6 7 8 9
3.数码管实现0-9的显示
先定义个数组SEG_Tab[10],把10个数字对应的16进制值存储进去
P70 = 0; //P70 对应最后那个数码管
P6 = SEG_Tab[0] //显示0
按按键便利数组SEG_Tab并给P6赋值,可以得到0-9 的显示
if(key2 == 0)
{
delay_ms(10);
if(key2 == 0)
{
if(num<9)
{
num++;
}
while(key2 == 0);
}
}
if(key == 0)
{
delay_ms(10);
if(key == 0)
{
if(num<9)
{
num--;
}
while(key == 0);
}
}
P6 = SEG_Tab[num] //显示
也可以加上蜂鸣器 ,每次按按键就会滴滴响,并切换数码数值
课后练习 :
1. H 0x76 J 0x0E L 0x48 N不会,这个要米字屏才可以显示吧 o 0xBB P 0XE3 U 0X6E t不会 r0x31
2.
int num = 0
if(key == 0)
{
delay_ms(10);
if(key == 0)
{
if(num<9)
{
num++;
}
else
{
num = 0;
}
while(key == 0);
}
}
P6 = SEG_Tab[num] //显示
if(key2 == 0)
{
delay_ms(10);
if(key2 == 0)
{
for(i = 0;i < num ;i++)
{
buzzer = 1;
delay_ms(200);
buzzer = 0;
delay_ms(200);
}
while(key == 0);
}
}
第十课 数码管的动态显示
1.数码管动态刷新原理
依次打开每个位的公共阳极端,关闭其他的,
同时 输入对应位的段码。
就行了,这是利用人眼的视觉惰性?
2.控制原理
不能延时太久超过20ms
3. 8位数码管点亮
曾加位码 数组 COM_Tab
增加显示 数组 Show_Tab
定义 int num 变量
P7 = COM_Tab[num];
P6 = SEG_Tab[Show_Tab[num]];
delay_ms(1);
num++;
if(num >7)
num = 0;
即可实现8位数码管点亮
课上后面有写了一个10s免单计数器,这里就不作记录了。主要是对动态数码管的应用
第十一课 定时器的使用
1.定时器的意义和作用
while循环中的每隔1ms加1 受while影响
引入中断的概念
主程序:背书
中断: 5分钟看锅
的定时器 每隔固定时间完成操作
可以脉冲计数 或替代delay
2. 使用原理 t0 1ms 中断
2.1 先设置功能位定时器
设置TMOD(AUXR)
2.2 设置分不分频
参考变速自行车理解12分配
设置AUXR 寄存器T0X12
2.3 设置工作模式
TMOD 中 T1_M1/T1_M0
0 0 16自动重载
0 1 16不自动重载
1 0 8自动重载(0-255)
1 1 不屏蔽中断的16自动重载
2.4 定时器 0/1 控制寄存器 TCON
TF0软件清0
TR0 软件写1
2.5 中断
EA 总中断
ET0 0 进制中断
1允许中断
3.定时器应用
手册上有个很清晰的定时器0 16位计数器的流程图
TMOD = 0x00; //模式 0
TL0 = 0x30; //24M 1ms
TH0 = 0xF8;
TR0 = 1; //启动定时器
ET0 = 1; //使能定时器中断
EA = 1;
void tim0_isr() interupt 1
{
//在这写中断函数的代码
}
stc-isp 定时器计算器很好用
课后练习:
void Timer0Init(void) //10毫秒@24.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xE0; //设置定时初始值
TH0 = 0xB1; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void tim0_isr() interupt 1
{
if(num>100)
{
clock++; //时间变量(s)
num = 0;
}
}
sec = clock % 7200;
min = clock /60 %60;
hour = clock /7200;
练习2
在增加一个变量pasue
按键按下时pause取反
pasue 为0 时关闭 中断 EA = 0;
为1 时开启 中断;
第十二课 计数器
1.计数器的用途
马达 编码器
2.计数器配置
T1_C/T 置1为计数器
T0_GATE 控制开关
TH1 TL1 计数用的
3.计数器应用
TMOD = 0x40; //计数模式
TL1 = 0xff;
TH1 = 0xff;
TF1 = 1;
TR1 = 1;
ET0 = 1;
EA = 1;
void Timer0_Isr(void) interrupt 3
{
P60 = !P60;
}
M法测速
n=M0/CT0
电机测速这里没理解太好,先记上,后面再来重新详细看一下
直流电机接上直流电就转,脉冲是哪里出现的?
题目中是供电回路接采样电阻,这只能测量出一个电压啊?
还是说供电时PWM形式的,PWM的频率和速度没关啊。
第十三课 简易多任务处理
这节课内容好多
1.回顾
GPIO 应用 和 TIM
重点清理程序的逻辑电路
2.模块化编程 .c .h
LED&数码管 led_seg.c (.h)
按键 key.c(.h)
蜂鸣器 beep.c(.h)
定时器 tim.c(.h)
函数添加注释
添加软件头
.h 中添加引脚定义
sbit name = P10;
#define name P10
函数
定义
声明
调用
extern
a.c 中 引用 b.c 的变量要加
bdata
可以寻址每个位
u8 bdata LED = 0x00;
sbit LED0 = LED^0;
sbit LED1 = LED^1;
3.工程文件编写
这里将之前的代码都整理了一遍
拆分成了4个模块,
在key模块中引入了状态机的概念,
实现了短按,长按等功能,
记住一个模块一个.c.h
声明放到.h 中
作业
这个可以用delay 或者 定时器实现。
void Timer0Init(void) //20毫秒@24.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xC0; //设置定时初始值
TH0 = 0x63; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void timer0_isr inturrpt 1
{
if(num1>10)
{
LED0 = ~LED0;
num1 = 0;
}
if(num2>20)
{
LED1 = ~LED1;
num2 = 0;
}
}
第十四课 矩阵键盘
1.矩阵按键是什么
GPIO的最后一个应用。
减少io口的运用
程序会变复杂
(好像见过专门驱动的芯片 spi协议的)
2.矩阵按键的控制原理
先0-3 输出第电平 6-7 输出高电平
如果有按键按下,那一列io就变低电平 判断哪一列
后0-3 输出高电平 6-7输出低电平
按下那一行的io就会变成低电平,判断出哪一列
3.矩阵按键程序的编写
u8 MaterixKey_Read()
{
u8 keystate; //状态
u8 key_val = 0;
MaterixKey = 0xC0;
delay_ms(10);
keystate = MateixKey ^ 0xC0;
MaterixKey = 0x0f;
delay_ms(10);
keystate |= (MateixKey ^ 0x0f);
printf("0x%02x \r\n",keystate);
switch(keystate)
{
case 0x41: key_val = 1;
break;
case 0x42: key_val = 2;
break;
case 0x44: key_val = 3;
break;
case 0x48: key_val = 4;
break;
case 0x81: key_val = 5;
break;
case 0x82: key_val = 6;
break;
case 0x84: key_val = 7;
break;
case 0x88: key_val = 8;
break;
default: key_val = 0;
break;
}
KEY_NUM = MaterixKey_Read();
SEG7 = KEY_NUM;
return keystate;
}
第十五课 外部中断
1.中断和中断系统
cpu暂停,处理紧急事件,处理完继续原来的工作
相应优先级高的中断
中断可以独立开关
部分优先级可以设置
2.什么是外部中断
外部电平变化产生的中断
写着INT的引脚是外部中断口
3.外部中断的用法
外部中断0
IT0
IE0
EX0
EA
外部中断1
IT1
IE1
EX1
EA
外部中断x
INTxIF
EXn
EA
4.外部中断用法
IT0 = 1; //使能 INT0 上升沿和下降沿中断
EX0 = 1; //使能 INT0 中断
IE = 0;
EA = 1;
void INT0_Init() interrupt 0
{
LED0 = !LED0;
}
这节内容比较简单 外部中断也可以用做紧急按键,相比普通按键反应很及时。
|
|