完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一、寄存器
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发器来构成。 二、GPIO 1、GPIO口 以看出AHB总线包含RCC时钟控制,GPIO是属于APB2的。 GPIO端口B的地址从0x4001 0C00开始。接下来只寻找时钟使能寄存器的地址: 复位和时钟控制RCC的地址从0x4002 1000开始; 可以在6.3.7小节找到APB2外设时钟使能寄存器(RCC_APB2ENR),偏移地址是0x18,所以APB2的地址就是0x4002 1018。 看手册RCC_APB2ENR,位3是IOPBEN,名字是IO端口B时钟使能,就是我们想要的。把RCC_APB2ENR的位3赋值为1,就是开启GPIOB时钟。 控制LED需要输出高电平或是低电平,所以需要配置为输出。 由于STM32的每个IO都需要4个位来配置,所以一个32位的寄存器最大只能配置8个IO(32位的单片机的寄存器就是32位的)。STM32中,用端口配置低寄存器(GPIOx_CRL)来配置引脚Px0-Px7, 用端口配置高寄存器(GPIOx_CRH)来配置引脚Px8-Px15。 配置引脚PB8,使用的寄存器是GPIOB_CRH。下面我们来寻找这个寄存器的地址。 推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。 开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。 开漏是需要外接上拉电阻才可以输出高电平的,这里并不适合。所以需要设置为推挽输出。 所以我们控制LED延时闪烁也很简单,就是控制ODR寄存器先输出1,LED灯亮,延时一段时间,控制ODR寄存器先输出0,LED灯灭,一直循环,就能实现流水灯的效果。 代码如下: GPIOC_ODR &= ~(1<<13);//配置输出低电平0 GPIOC_ODR |= (1<<13);//配置输出高电平1 2、GPIO口的初始化: ①对于单个GPIO口的初始化如下 GPIO_InitTypeDef GPIO_InitStructure; 第一步:使能GPIOA的时钟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 第二步:设置GPIOA参数:输出OR输入,工作模式,端口翻转速率 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_6| GPIO_Pin_7| GPIO_Pin_8; //设定要操作的管脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz 第三步:调用GPIOA口初始化函数,进行初始化。 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA 第四步:调用GPIO-SetBits函数,进行相应为的置位。 GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出高 ②对于多个GPIO口的初始化如下 GPIO_InitTypeDef GPIO_InitStructure; 第一步:使能GPIOA,GPIOE的时钟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); 第二步:设置GPIOA,GPIOE参数:输出OR输入,工作模式,端口翻转速率 第三步:调用GPIOA口初始化函数,进行初始化。 第四步:调用GPIO-SetBits函数,进行相应为的置位。 ▶把第二、三、四步合并分别设置GPIOA和GPIOE 先设置GPIOA GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 第四个口,PA4 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz GPIO_Init(GPIOA,&GPIO-InitST); //根据设定参数初始化GPIOA GPIO_SetBits(GPIOA,GPIO_Pin_4); //输出高 再设置GPIOE GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 第三个口,PE3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz GPIO_Init(GPIOE,&GPIO-InitST); //根据设定参数初始化GPIOE GPIO_SetBits(GPIOE,GPIO_Pin_3); //输出高 1.配置时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启 GPIOB 端口时钟 2.初始化结构体 // @file stm32f10x_gpio.h typedef struct { uint16_t GPIO_Pin; /*!< 选择要配置的 GPIO 引脚 */ GPIOSpeed_TypeDef GPIO_Speed; /*!< 选择 GPIO 引脚的速率 */ GPIOMode_TypeDef GPIO_Mode; /*!< 选择 GPIO 引脚的工作模式 */ }GPIO_InitTypeDef; 3.配置输入输出模式 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; //输出模式为通用推挽输出 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4 ; //选定输出端口为GPIO_Pin_4 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz; //输出速度为2M GPIO_Init(GPIOA,&GPIO_InitStruct); 三、点亮流水灯 1、生成hex文件 首先创建工程: 三、点亮流水灯 1、生成hex文件 首先创建工程: 在在魔法棒中设置选择生成hex文件: 编写代码: 加入延时函数: //延时函数 void Delay_ms( volatile unsigned int t) { unsigned int i; while(t--) for (i=0;i<800;i++); } 代码如下: main.c /*GPIOA外设基地址*/ #define GPIOA_BASE 0x40010800 /*GPIOB外设基地址*/ #define GPIOB_BASE 0x40010C00 /*GPIOC外设基地址*/ #define GPIOC_BASE 0x40011000 /*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/ #define RCC_APB2ENR *((unsigned volatile int*)0x40021018) /*GPIOA寄存器地址,强制转换为指针*/ #define GPIOA_CRH *((unsigned volatile int*)0x40010804) #define GPIOA_ODR *((unsigned volatile int*)0x4001080C) /*GPIOB寄存器地址,强制转换为指针*/ #define GPIOB_CRL *((unsigned volatile int*)0x40010C00) #define GPIOB_ODR *((unsigned volatile int*)0x40010C0C) /*GPIOC寄存器地址,强制转换为指针*/ #define GPIOC_CRH *((unsigned volatile int*)0x40011004) #define GPIOC_ODR *((unsigned volatile int*)0x4001100C) /*延时函数*/ void Delay_ms( volatile unsigned int t) { unsigned int i; while(t--) for (i=0;i<800;i++); } /*主函数*/ int main() { RCC_APB2ENR|=1<<2; /*APB2-GPIOA外设时钟使能*/ RCC_APB2ENR|=1<<3; /*APB2-GPIOB外设时钟使能*/ RCC_APB2ENR|=1<<4; /*APB2-GPIOC外设时钟使能*/ GPIOA_CRH&=0xFFF0FFFF; /*设置位 清零*/ GPIOA_CRH|=0x00020000; /*PA12推挽输出*/ GPIOA_ODR&=1<<12; /*设置初始灯为亮*/ GPIOB_CRL&=0xFFFFFF0F; /*设置位 清零*/ GPIOB_CRL|=0x00000020; /*PB1推挽输出*/ GPIOB_ODR|=0<<1; /*设置初始灯为灭*/ GPIOC_CRH&=0xF0FFFFFF; /*设置位 清零*/ GPIOC_CRH|=0x02000000; /*PC14推挽输出*/ GPIOC_ODR|=0<<14; /*设置初始灯为灭*/ while(1) { GPIOA_ODR&= ~(1<<12); /*PA12高电平*/ Delay_ms(3000000); GPIOA_ODR|= (1<<12); /*PA12低电平*/ Delay_ms(3000000); GPIOB_ODR&= ~(1<<1); /*PB1高电平*/ Delay_ms(3000000); GPIOB_ODR|= (1<<1); /*PB1低电平*/ Delay_ms(3000000); GPIOC_ODR&= ~(1<<14); /*PC14高电平*/ Delay_ms(3000000); GPIOC_ODR|= (1<<14); /*PC14低电平*/ Delay_ms(3000000); } } CH341SeSetep也安装上 打开界面如图所示: 如果 USB 转串口驱动安装成功,USB 线跟板子连接没有问题,在计算机->管理->设备管理器->端口中可识别到串口。 打开C8T6数据手册,查找TXD和RXD管脚位置 PA9——TX PA10——RX
设置bps和烧入的hex文件之后点击开始编程,上图所示就是程序烧入成功的 3、结果 四、总结 这次的实验内容是用寄存器的GPIOA、GPIOB、GPIOC口来点亮流水灯,在这个过程中,遇到了很多的问题,首先是关于寄存器的初始化,必须要查阅stm32f103c8芯片的手册,还在其他的博客上查阅关于面包板的使用,还有就是关于实物的连接都遇到了困难,不过好在网上的资料很多,在翻阅资料的过程中,学到了很多的东西,还有对于嵌入式的了解更加深入了。 |
|
|
|
只有小组成员才能发言,加入小组>>
3318 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9063 浏览 16 评论
4088 浏览 18 评论
1182浏览 3评论
608浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
600浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 21:12 , Processed in 1.031720 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号