完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一、实验目的:
显示0-9999的任意数字(包括小数) 那为什么要做这个项目呢,其实因为很多传感器读出来的数据都是浮点数类型的数据,如超声波模块,温度传感器,压力传感器。为了显示结果,可以采用串口打印,数码管,oled或者lcd屏等,其中数码管的成本较低,因此本次实验采用了5461AS-1型号的数码管。 这个数码高管是位选高电平,段选低电平亮 1.1 IO分配 [tr]功能IO功能IO[/tr]
本次实验GPIO只用到了输出功能,STM32的所有输出功能如下所示: [tr]代码含义[/tr]
1.2.1 GPIO初始化
void gpio_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOD, ENABLE); // 使能PB端口与PD端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; // PE8->a GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz GPIO_Init(GPIOE, &GPIO_InitStructure); // 根据设定参数初始化PE8-PE15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; // PD0->w1 GPIO_Init(GPIOD, &GPIO_InitStructure); // 根据设定参数初始化PD0-PD3 } 1.2.2 GPIO常用置高置低函数(以PB5为例) GPIO_ResetBits(GPIOB, GPIO_Pin_5); // 置低-0 PBout(5)=0; GPIO_SetBits(GPIOB, GPIO_Pin_5); // 置高-1 PBout(5)=1; 当确定了端口以后,建议用第二种方式去写。 二、数四位码管实验主体 编辑器:Keil5+CLion Keil5:单片机程序编写 CLion:数据处理程序编写(因为常用它的Pycharm,很喜欢它的风格) 2.1 实现单个任意数字的显示
在前面实验目的中说明了该数码管是段选是低电平选中,位选是高电平选中。这是由内部电路决定的,大家拿到一个数码管的时候可以有两种方式去确定段选与位选的高低特性:
PDout(0) = 1; PDout(1) = 0; PDout(2) = 1; PDout(3) = 1; 展示六的数字: PEout(8) = 1; PEout(9) = 0; PEout(10) = 1; PEout(11) = 1; PEout(12) = 1; PEout(13) = 1; PEout(14) = 1; PEout(15) = 0; 因此可以将段选与位选定义两个数组,用管脚数字作为数组里的数据,这也是为什么IO分配时段选的管脚都是PD,位选的管脚都是PE。 由段选为例: 第X个数码管对应数据[4] [4] = {{0,1,1,1},{1,0,1,1},{1,1,0,1},{1,1,1,0}}; 段选[4] = {0,1,2,3}; 则利用for循环则可以一一赋值 2.1.1 定义数字表以及数码管段选表 // 四位数码管位选表 int table[20][8] = {{1,1,1,1,1,1,0,0},// 0-9 数字表码 {0,1,1,0,0,0,0,0}, {1,1,0,1,1,0,1,0}, {1,1,1,1,0,0,1,0}, {0,1,1,0,0,1,1,0}, {1,0,1,1,0,1,1,0}, {1,0,1,1,1,1,1,0}, {1,1,1,0,0,0,0,0}, {1,1,1,1,1,1,1,0}, {1,1,1,1,0,1,1,0}, {1,1,1,1,1,1,0,1},// 0.-9. 小数数字表码 {0,1,1,0,0,0,0,1}, {1,1,0,1,1,0,1,1}, {1,1,1,1,0,0,1,1}, {0,1,1,0,0,1,1,1}, {1,0,1,1,0,1,1,1}, {1,0,1,1,1,1,1,1}, {1,1,1,0,0,0,0,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,0,1,1,1}}; // 四位数码管段选表 int channel_pin[4][4]= {{0,1,1,1},{1,0,1,1},{1,1,0,1},{1,1,1,0}}; // 选择某一位对应的电平数组 2.1.2 消影 消影是数码管必须要的一个环节,那什么是消影呢?其实就是消除上一次显示留下来的数字残留,大家可以分别烧入无消影代码与有消影代码进行测试,显示多个不同数字,会发现,无消影的代码后续显示会出错。因此消影是不可缺的一部分。 原理如下:关闭所有段选,关闭所有位选,简单说就是啥也不亮。 选择第二个数码管: PDout(0) = 1; PDout(1) = 0; PDout(2) = 1; PDout(3) = 1; 展示六的数字: PEout(8) = 1; PEout(9) = 0; PEout(10) = 1; PEout(11) = 1; PEout(12) = 1; PEout(13) = 1; PEout(14) = 1; PEout(15) = 0; 因此可以将段选与位选定义两个数组,用管脚数字作为数组里的数据,这也是为什么IO分配时段选的管脚都是PD,位选的管脚都是PE。 由段选为例: 第X个数码管对应数据[4] [4] = {{0,1,1,1},{1,0,1,1},{1,1,0,1},{1,1,1,0}}; 段选[4] = {0,1,2,3}; 则利用for循环则可以一一赋值 2.1.1 定义数字表以及数码管段选表 // 四位数码管位选表 int table[20][8] = {{1,1,1,1,1,1,0,0},// 0-9 数字表码 {0,1,1,0,0,0,0,0}, {1,1,0,1,1,0,1,0}, {1,1,1,1,0,0,1,0}, {0,1,1,0,0,1,1,0}, {1,0,1,1,0,1,1,0}, {1,0,1,1,1,1,1,0}, {1,1,1,0,0,0,0,0}, {1,1,1,1,1,1,1,0}, {1,1,1,1,0,1,1,0}, {1,1,1,1,1,1,0,1},// 0.-9. 小数数字表码 {0,1,1,0,0,0,0,1}, {1,1,0,1,1,0,1,1}, {1,1,1,1,0,0,1,1}, {0,1,1,0,0,1,1,1}, {1,0,1,1,0,1,1,1}, {1,0,1,1,1,1,1,1}, {1,1,1,0,0,0,0,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,0,1,1,1}}; // 四位数码管段选表 int channel_pin[4][4]= {{0,1,1,1},{1,0,1,1},{1,1,0,1},{1,1,1,0}}; // 选择某一位对应的电平数组 2.1.2 消影 消影是数码管必须要的一个环节,那什么是消影呢?其实就是消除上一次显示留下来的数字残留,大家可以分别烧入无消影代码与有消影代码进行测试,显示多个不同数字,会发现,无消影的代码后续显示会出错。因此消影是不可缺的一部分。 原理如下:关闭所有段选,关闭所有位选,简单说就是啥也不亮。 2.1.3 主体代码如下 void ShowNum(int w, int num) { /* w: 传入需要显示的位置(2) num : 传入需要显示的数字(8) */ int j; int weixuan[4] = {w1,w2,w3,w4}; // 位选数组 int duanxuan[8] = {a,b,c,d,e,f,g,h}; // 段选数组 // 消除重影 // 清除位选 for(j=0;j<4;j++) PDout(weixuan[j]) = 1; // 清除段选 for(j=0;j<8;j++) PEout(duanxuan[j]) = 0; // 选择第几个数码管亮 for(j=0;j<4;j++) PDout(weixuan[j]) = channel_pin[w-1][j]; // w-1是因为数组的首元素是0,而传入的位是 // 选择显示什么数字 for(j=0; j<8;j++) PEout(duanxuan[j]) = table[num][j]; } 2.2 数据处理 由1的代码显然,假设显示13.78,因此 ShowNum(1,1);ShowNum(2,13);ShowNum(3,7);ShowNum(4,8);根据思路综合为以下的代码 num[4] = {1,13,7,8}; for(i=0;i<4;i++) // 四位数码管显示数字 { ShowNum(i+1,num); // i+1是因为数组的首元素是0,而传入的位是1 } 其中13这个数字是因为在2.1.1定义数字表时,有小数点的数字与纯数字的位置相差了10。 由此可见,我们需要将浮点数变为四位整数型数组 可分为以下几步: step1:记录小数点位置, step2:float—int(13.78 - 1378),并限制位数为四位 step3:1378-{1,3,7,8} step4:{1,3,7,8}->{1,13,7,8},放入小数点 ———————————————— 版权声明:本文为CSDN博主「红颜时光」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_42730527/article/details/114934144 由于四位数码管数据范围根据小数点可分为以下几类 可以用if语句进行分类实现。 2.2.2浮点数变为整数,并限制为四位 这个其实很简单,在上述分类中,以13.78568为例 13.78568 × 100 = 1378.568 13.78568 times 100 = 1378.56813.78568×100=1378.568 再将数字转换为int类型,既可以得到1378。同意在每个分类中只要更换乘数即可。 ———————————————— 版权声明:本文为CSDN博主「红颜时光」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_42730527/article/details/114934144 2.2.2浮点数变为整数,并限制为四位 这个其实很简单,在上述分类中,以13.78568为例 13.78568 × 100 = 1378.568 13.78568 times 100 = 1378.568 13.78568×100=1378.568 再将数字转换为int类型,既可以得到1378。同意在每个分类中只要更换乘数即可。 2.2.3 整数变为整数型数组 以1378为例 综上可得,每一位数字是倒序取出,由于在每个判断中都会用到这个,因此将它写为一个函数,返回为int类型的数组 void NumList(int *num_list,int num) { /* num: 传入的四位整型数字(1378) *num_list : 需要返回的整型数组({1,3,7,8}) */ int i, temp=0; for(i=0;i<4;i++) { temp = num%10; // 倒着取余数 num = num/10; // 去掉末尾 num_list[4-i-1] = temp; // 存入数组 } 上面说了,返回int类型的数组,那为什么是void呢?其实num_list这个变量就是返回的数组。 在C语言里返回数组有两种方式:
2.2.4 放入小数点 根据公式2,直接对2.2.3返回的数组进行修改即可。 2.2.5 数据处理代码 传入浮点数,返回整数型数组,当然返回形式依然用上述的第二种方式。 void DisplayNumList(int *num_list_d, float num) { /* num: 传入的浮点型型数字(13.78) *num_list_d : 需要返回的整型数组({1,13,7,8}) */ int n,i; // 判断浮点数字的小数点位置 if(0 n = num*1000; NumList(num_list_d,n); num_list_d[0] += 10; // 加10是因为在位选码中,3与3.的位置相差了10 } if(10<=num && num<100) { n = num*100; NumList(num_list_d,n); num_list_d[1] += 10; } if(100<=num && num<1000) { n = num*10; NumList(num_list_d,n); num_list_d[2] += 10; } if(1000<=num && num<10000) { n = num; NumList(num_list_d,n); } // 超出最大数字9999时显示9999 if(10000 < num ) { for(i=0;i<4;i++) num_list_d = 9; } } 2.3 数码管显示浮点数 void Display(float num_f) { /* num_f : 传入需要显示的数字(13.78) */ int i,t; int num[4] = {0}; // 接收处理浮点型数字后的数组,要初始化 DisplayNumList(num, num_f); // 传入浮点数子,返回处理后的数组 for(t=0;t<10000;t++) // 延时是为了增加显示时间,经测试t>6000为好 { for(i=0;i<4;i++) // 四位数码管显示数字 { ShowNum(i+1,num); // i+1是因为数组的首元素是0,而传入的位是1 } } } 根据之前所有的思路,其实就是一个最终的整合,但是这里可以发现在外层嵌套了一个很大的for循环,这样做的目的是什么的? 延长显示时间,数码管里绝对不能出现delay函数,因为delay函数就是什么也不干,干等着,因此为了延长显示时间,则对显示函数进行for循环即可,若是需要更长的时间,可以多层循环进行嵌套。 三、结果呈现 四、完整代码 /* title: Four-digit Digital Tube author: Joylen Huang */ #include "sys.h" #include "delay.h" #include "usart.h" // 函数定义 void NumList(int *num_list,int num); // 4位整数型数字变整数型数组 void DisplayNumList(int *num_list_d, float num); // 浮点数变为四位数码管可识别的整数型数组 void gpio_Init(void); // IO口初始化函数 void ShowNum(int w, int num); // 四位数码管显示任意端口任意数字 void Display(float num_f); // 最终显示函数 // PDout(w1)位选定义 #define w1 0 #define w2 1 #define w3 2 #define w4 3 // PEout(a) 段选定义 #define a 8 #define b 9 #define c 10 #define d 11 #define e 12 #define f 13 #define g 14 #define h 15 // 四位数码管位选表 int table[20][8] = {{1,1,1,1,1,1,0,0},// 0-9 数字表码 {0,1,1,0,0,0,0,0}, {1,1,0,1,1,0,1,0}, {1,1,1,1,0,0,1,0}, {0,1,1,0,0,1,1,0}, {1,0,1,1,0,1,1,0}, {1,0,1,1,1,1,1,0}, {1,1,1,0,0,0,0,0}, {1,1,1,1,1,1,1,0}, {1,1,1,1,0,1,1,0}, {1,1,1,1,1,1,0,1},// 0.-9. 小数数字表码 {0,1,1,0,0,0,0,1}, {1,1,0,1,1,0,1,1}, {1,1,1,1,0,0,1,1}, {0,1,1,0,0,1,1,1}, {1,0,1,1,0,1,1,1}, {1,0,1,1,1,1,1,1}, {1,1,1,0,0,0,0,1}, {1,1,1,1,1,1,1,1}, {1,1,1,1,0,1,1,1}}; // 四位数码管段选表 int channel_pin[4][4]= {{0,1,1,1},{1,0,1,1},{1,1,0,1},{1,1,1,0}}; // 选择某一位对应的电平数组 void NumList(int *num_list,int num) { /* num: 传入的四位整型数字(1378) *num_list : 需要返回的整型数组({1,3,7,8}) */ int i, temp=0; for(i=0;i<4;i++) { temp = num%10; // 倒着取余数 num = num/10; // 去掉末尾 num_list[4-i-1] = temp; // 存入数组 } } void DisplayNumList(int *num_list_d, float num) { /* num: 传入的浮点型型数字(13.78) *num_list_d : 需要返回的整型数组({1,13,7,8}) */ int n,i; // 判断浮点数字的小数点位置 if(0 n = num*1000; NumList(num_list_d,n); num_list_d[0] += 10; // 加10是因为在位选码中,3与3.的位置相差了10 } if(10<=num && num<100) { n = num*100; NumList(num_list_d,n); num_list_d[1] += 10; } if(100<=num && num<1000) { n = num*10; NumList(num_list_d,n); num_list_d[2] += 10; } if(1000<=num && num<10000) { n = num; NumList(num_list_d,n); } // 超出最大数字9999时显示9999 if(10000 < num ) { for(i=0;i<4;i++) num_list_d = 9; } } void gpio_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOD, ENABLE); // 使能PB端口与PD端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; // PE8->a GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz GPIO_Init(GPIOE, &GPIO_InitStructure); // 根据设定参数初始化PE8-PE15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; // PD0->w1 GPIO_Init(GPIOD, &GPIO_InitStructure); // 根据设定参数初始化PD0-PD3 } void ShowNum(int w, int num) { /* w: 传入需要显示的位置(2) num : 传入需要显示的数字(8) */ int j; int weixuan[4] = {w1,w2,w3,w4}; // 位选数组 int duanxuan[8] = {a,b,c,d,e,f,g,h}; // 段选数组 // 消除重影 // 清除位选 for(j=0;j<4;j++) PDout(weixuan[j]) = 1; // 清除段选 for(j=0;j<8;j++) PEout(duanxuan[j]) = 0; // 选择第几个数码管亮 for(j=0;j<4;j++) PDout(weixuan[j]) = channel_pin[w-1][j]; // w-1是因为数组的首元素是0,而传入的位是1 // 选择显示什么数字 for(j=0; j<8;j++) PEout(duanxuan[j]) = table[num][j]; } void Display(float num_f) { /* num_f : 传入需要显示的数字(13.78) */ int i,t; int num[4] = {0}; // 接收处理浮点型数字后的数组,要初始化 DisplayNumList(num, num_f); // 传入浮点数子,返回处理后的数组 for(t=0;t<10000;t++) // 延时是为了增加显示时间,经测试t>6000为好 { for(i=0;i<4;i++) // 四位数码管显示数字 { ShowNum(i+1,num); // i+1是因为数组的首元素是0,而传入的位是1 } } } int main(void) { float num_f; // 定义变量,必须放在最前面 gpio_Init(); // IO初始化 delay_init(); // 延时函数初始化 // 主循环函数 while(1) { num_f = 13.78; Display(num_f); num_f = 25.96; Display(num_f); } } |
|||
|
|||
只有小组成员才能发言,加入小组>>
2565 浏览 0 评论
762浏览 1评论
521浏览 0评论
275浏览 0评论
456浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 17:55 , Processed in 1.225615 second(s), Total 51, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号