STM32F072RB 模拟板,本身没有显示器,如果能加装一个,那么在实验的时候可以监看程式进行状态就方便许多了。于是我就用手边的 LCD 1602,做一个试试!以下就是整个过程。
LCD1602 规格資料
LCD1602 是一个非常普遍的材料,规格同一,书面資料也是相互抄袭,从网络上很轻易的就能找到,我这里附上的是英文的資料,中文資料可以自己再去找找。 LCD 1602 硬件长相 接脚定义 一个很重要的指令表 写程式的时候会一直参考这个表格,特别要注意 RS 和 R/W 这两个脚位的讯号变化。 各个指令的说明 编写属于 LCD1602 的 command 档 我依照 LCD 1602 的指令规定,逐个编写指令放置在 LCD1602_cmd.c 的档案里。内容包刮 F072BR 的接脚定义,以下列了几个觉得是重要的: a. void GPIO_Configuration(void);// 设定GPIOC 和 GPIOB 的脚位定义; b. void GPIO_Write(u8 temp); //写(输出讯号时候)脚位要重新定义; c. void LCD1602_Init(void);// 执行 LCD1602 重置的动作-- 注意要适度的加入Delay()。 d. u8 LCD_CheckBusy(void);// 这一个功能是 最常使用的功能。因为要常常检查LCD是不是在忙碌状态。传回的資料还附带了LCD游标的目前位置,所以设成U8, 传回一个 byte 的 地址。 e. void LCD1602_SetCursor( u8 x, u8 line );//加上line 位置的cursor 设定. f. void GPIOB_SetBits(u8 GPIOB_Pin); 和 void GPIOB_ResetBits(u8 GPIOB_Pin); 是为了方便 header 档加上的。 g. 其他的因为很简单,有兴趣自己对照以下就看得懂,也可以自己改一改。 以下就是 LCD1602_cmd.c 的代码。
#include "lcd1602.h"
#include "stm32f0xx.h" // File name depends on device used
//---------------------------------
void GPIO_Configuration(void)
{ //------------GPIOC0_7_init(void) --define Port C, pin 0~7
RCC->AHBENR |= 0x1ul<<19; // set GPIOC on
GPIOC->MODER &= ~(0xfffful); //clear MODER
GPIOC->MODER |= 0x5555ul; //set Moder to bx0101 -->output
GPIOC->OSPEEDR &= ~0xfffful; // clear OSPEEDR
GPIOC->OSPEEDR |= 0x5555ul; // set OSPEEDR to bx0101 medium speed
//-------------------void GPIOB0_2_init(void) --define Port B, pin 0~2
//GPIOC->OTYPER &= ~(0x1ul<<7); // GPIOC to OC
RCC->AHBENR |= 0x1ul<<18; // set GPIOC on
GPIOB->MODER &= ~(0x3ful); //clear MODER
GPIOB->MODER |= 0x15ul; //set Moder to bx0101 -->output
GPIOB->OSPEEDR &= ~0x3ful; // clear OSPEEDR
GPIOB->OSPEEDR |= 0x15ul; // set OSPEEDR to bx0101 medium speed
}
//------------------------------------
u8 GPIO_ReadAddr(u8 temp){
LCD_RS_H(); //=0;
LCD_RW_H(); //=1;
GPIOC->MODER |= 0x2ul <<7; //set GPIOC bit 7 Moder to bx11 -->intput
temp = GPIOC->IDR ;
return temp;
}
//--------------------------------------------
void GPIO_Write(u8 temp){
GPIOC->MODER &= ~(0xfffful); //clear MODER
GPIOC->MODER |= 0x5555ul; //set Moder to bx0101 -->output
GPIOC->ODR = temp;
}
//--------------------------------------------
void LCD_delay(u32 x){
u32 i, j;
for(i=0; i<x; i++){for(j=0; j<1000; j++) ;
}
}
//-------------------------------
void LCD1602_Init()
{
LCD1602_ClearScreen();
LCD_delay(41);
func_set(1,1,0); //0x28 DL=1(8-bit), N=0(1-line), F=1(5x11)
LCD_delay(41);
LCD_delay(5);
LCD_entry_mod(1, 0); // ID =1, SH=0
LCD_delay(5);
cusr_ctrl(1,1,1); // Dp =1, csr =1, blk =1
}
//------------------------------------
u8 LCD_CheckBusy(void)
{
u8 sta;
LCD_RS_L(); //=0;
LCD_RW_H(); //=1;
GPIOC->MODER &= ~(0xfffful); //clear MODER
GPIOC->MODER |= 0xaaaaul; //set Moder to bx1010 -->input
do{
LCD_EN_H(); // =1;
LCD_delay(5);
sta = (GPIOC ->IDR);
LCD_EN_L(); // =0;
}while(sta & 0x80); //BF=1, LCD is busy
return sta;
}
//------------------------------------
void LCD1602_WriteCmd( u8 cmd )
{
u8 addr = LCD_CheckBusy(); //to get cursor address
LCD_RS_L(); //LCD_RS = 0;
LCD_RW_L(); //LCD_RW = 0;
GPIO_Write(cmd); // GPIO_OutData(Cmd);
LCD_EN_H(); // = 1;
LCD_delay(5);
LCD_EN_L(); // = 0;
}
//------------------------------------
void LCD1602_WriteData( u8 data )
{
u8 addr = LCD_CheckBusy(); //o get cursor address
LCD_RS_H(); //=1;
LCD_RW_L(); //=0;
GPIO_Write( data); // GPIO_OutData(Dat);
LCD_EN_H(); //=1;
LCD_delay(5);
LCD_EN_L(); //EN = 0;
}
//------------------------------------
void LCD1602_SetCursor( u8 x, u8 line )
{
u8 addr;
if (line == 0) addr = 0x00 + x;
if (line == 1) addr = 0x40 + x;
LCD1602_WriteCmd(addr | 0x80);
}
//------------------------------------
void LCD1602_Show_Str( u8 x, u8 y, u8 *str )
{
u16 count =0;
LCD1602_SetCursor(x, y);
while(*str != '\0')
{
LCD1602_WriteData(*str++); count++;
if (count>15){LCD1602_SetCursor(0, 0x40ul);}
}
}
//------------------------------------
void LCD1602_DisNumber(u8 x,u8 y, u8 Num) //change line check
{
LCD1602_SetCursor(x,y);
LCD1602_WriteData(0x30+Num/10);
LCD1602_SetCursor(x+1, y);
LCD1602_WriteData(0x30+Num%10);
}
//-------------------------------------
void LCD1602_DisChar(u8 x, u8 y, u8 ch)
{
LCD1602_SetCursor(x, y); //set curcor to upper or lower line
LCD1602_WriteData(ch);
}
//------------------------------------
//RS ->PB0, Rw ->PB1, EN ->PB2
void GPIOB_SetBits(u8 GPIOB_Pin)
{
GPIOB->ODR |= 0x1ul <<GPIOB_Pin; //set to 1
}
//------------------------------------
void GPIOB_ResetBits(u8 GPIOB_Pin)
{
GPIOB->ODR &= ~(0x1ul << GPIOB_Pin); // set 0
}
//------------------------------------
void LCD1602_ClearScreen() // set screen by char 0x20ul
{
LCD1602_WriteCmd(0x01);
}
//-----------------------------------
void LCD1602_currest() //cursor back to 0,0
{
LCD1602_WriteCmd(0x02ul);
}
//------------------------------------
void LCD_entry_mod(u8 ID, u8 SH){
u8 cmd = 0x04ul;
if(ID==1){ cmd |= 0x1ul << 1;}
if(SH==1){ cmd |= 0x1ul ;}
LCD1602_WriteCmd(cmd);
}
void cusr_ctrl(u8 Dp,u8 csr,u8 blk){
u8 cmd = 0x8ul;
if(Dp==1){ cmd |= 0x1ul << 2;} //Dp =1()
if(csr==1){ cmd |= 0x1ul << 1;} //csr =1()
if(blk==1){ cmd |= 0x1ul ;} // blk =1()
LCD1602_WriteCmd(cmd);
}
void dp_shift(u8 SC,u8 RL){
u8 cmd = 0x10ul; ///0b0001 0000
if(SC==1){ cmd |= 0x1ul << 3;} // sc=1 ()
if(RL==1){ cmd |= 0x1ul << 2;} // RL=1 ()
LCD1602_WriteCmd(cmd);
}
void func_set(u8 DL,u8 N, u8 F){ //
u8 cmd = 0x20ul; //bx0010 0000
if(DL==1){ cmd |= 0x1ul << 4;} // DL=1(8-bit), DL=0(4-bit)
if(N==1){ cmd |= 0x1ul << 3;} // N=1(2-line), N=0(1-line)
if(F==1){ cmd |= 0x1ul << 2;} // F=1(5x11), F=0(5x8),
LCD1602_WriteCmd(cmd);
}
void setCGRAM_addr(u8 addr){
u8 cmd = 0x40ul + addr; // DB6 =1
LCD1602_WriteCmd(cmd);
}
void setDDRAM_addr(u8 addr){
u8 cmd = 0x80ul + addr; // DB7 =1
LCD1602_WriteCmd(cmd);
}
//----------------------------------
u8 LCD_ReadADDR(void)
{
u8 sta;
LCD_RS_L(); //=0;
LCD_RW_H(); //=1;
GPIOC->MODER &= ~(0xfffful); //clear MODER
GPIOC->MODER |= 0xaaaaul; //set Moder to bx1010 -->input
LCD_EN_H(); // =1;
LCD_delay(5);
sta = (GPIOC ->IDR);
LCD_EN_L(); // =0;
return sta;
}
//------------------------------
//--------show line1 line2 --------------------------------------
void LCD1602_show(u8 *line1, u8 *line2){
u8 i;
LCD1602_ClearScreen();
LCD_entry_mod(1,0); //change 0 =>revers, 1= whole screen
LCD1602_SetCursor( 0, 0);
for(i=0;i<16;i++){
LCD1602_WriteData(line1[i]) ;}
LCD1602_SetCursor( 0, 1);
for(i=0;i<16;i++){
LCD1602_WriteData(line2[i]) ;}
}
//******************************************
编写属于 LCD1602 的 header 档 下面来谈谈 header 档的 应用。 以前学的时候都知道 C语言的可携带性/可移植性 很好,是因为有 header 档案,由于每经验所以都是一知半解。 从上面的图的左边可以看到 我把 main.c 主档 和 LCD1602_cmd.c 放在同一个档案夹。就是在编译的时候是一起操作的。至于如何链接起来执行就要靠这个 include
#include "lcd1602.h"
同时在 main.c 和 LCD1602_cmd.c 都要有。 以前不了解 h 档 都是把 #include “lcd1602_cmd.c” 当成方法。可以看到在 main.c 里面 我把 #include “lcd1602_cmd.c” 注解掉,依然可以执行。 下边的代码就是我编写的 “lcd1602.h” 档。
#ifndef __LCD1602_H
#define __LCD1602_H
/***************************????????????*****************************/
#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned int
#define RS 0
#define RW 1
#define EN 2
#define BF 7
#define LCD_RS_H() GPIOB_SetBits( RS ) //1602 data
#define LCD_RS_L() GPIOB_ResetBits( RS ) //1602 command
#define LCD_RW_H() GPIOB_SetBits( RW ) //1602 readdata
#define LCD_RW_L() GPIOB_ResetBits( RW ) //1602 writedata
#define LCD_EN_H() GPIOB_SetBits( 2 ) //1602 enable
#define LCD_EN_L() GPIOB_ResetBits( 2 )
#define LCD_clr_dp LCD_WriteCmd(ox1ul);
#define LCD_csr_rt LCD_WriteCmd(ox2ul);
#define DATAOUT( x ) GPIO_Write( GPIOA, x ) //1602?8??????
#define upLine_s 0x00ul
#define downLine_s 0x40ul
void GPIO_Write(u8 temp);
void GPIO_Configuration(void);
void LCD1602_Init(void);
u8 LCD_CheckBusy(void);
void LCD1602_Wait_Ready(void);
void LCD1602_WriteCmd( u8 cmd );
void LCD1602_WriteData( u8 data );
void LCD1602_SetCursor( u8 x, u8 line );
void LCD1602_Show_Str( u8 x, u8 y, u8 *str );
void LCD1602_DisNumber(u8 x,u8 y, u8 Num);
void LCD1602_DisChar(u8 x, u8 y, u8 ch);
void GPIOB_SetBits(u8 GPIOB_Pin);
void GPIOB_ResetBits(u8 GPIOB_Pin);
void LCD1602_ClearScreen(void);
void LCD1602_currest(void);
void LCD_entry_mod(u8 ID, u8 SH);
void cusr_ctrl(u8 Dp,u8 csr,u8 blk);
void dp_shift(u8 SC,u8 RL);
void func_set(u8 DL,u8 N, u8 F);
void setCGRAM_addr(u8 addr);
void setDDRAM_addr(u8 addr);
void LCD_delay(u32 x);
u8 LCD_ReadADDR(void);
void LCD1602_show(u8 *line1,u8 *line2);
#endif
下面列的是另一个样本,可以参考一下 h 档的重要结构
time3.h
#ifndef _TIME3_H_
#define _TIME3_H_
void TIM3_Int_Init(unsigned short psc, unsigned short arr);
#endif
main.c 档
以下main.c 档的内容,我留下许多实验的痕迹,有兴趣的人可以自己修改看看。下一步再加上 USART 的外接传输就可以透过手机传讯息到 F072 的主板了
/** Project name : LCD 1602
* GPIOC 0~7: LCD data b0~b7
* RS ->PB0, Rw ->PB1, EN ->PB2
--------------------------------------------------------------------------------------*/
#include <stdio.h>
#include "stm32f0xx.h" // File name depends on device used
#include "RTE_Components.h" // Component selection
#include "lcd1602.h"
//#include "bt2uart.h"
//#include "lcd1602_cmd.c"
extern void stdout_init (void);
//extern void GPIO_Configuration(void);
volatile uint32_t msTicks; // Counter for millisecond Interval
#define NUM_KEYS 1 /* Number of available keys */
/* Keys for NUCLEO Board */
extern void Config_PA910(void); // for Bluetooth PA.9(Tx)->HC05(Rx), PA.10(Rx)->HC05(Tx)
extern void Config_uart1(void); // for BlueTooth
extern void PutCha(u8 ch);
#define USER 1
#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned int
/*--------------------------------------------------------------------------------*/
// SysTick Interrupt Handler
/*--------------------------------------------------------------------------------*/
void SysTick_Handler (void)
{
msTicks++; // Increment Counter
}
/*--------------------------------------------------------------------------------*/
// Delay: delay a number of Systicks
/*--------------------------------------------------------------------------------*/
void Delay(uint32_t dlyTicks){
uint32_t currentTicks;
currentTicks = msTicks;
while( (msTicks - currentTicks) < dlyTicks ){
__NOP();
}
}
/**-----------------------------------------------------------------------------
* @brief Configures the System clock frequency, AHB/APBx prescalers and Flash
* settings.
* @note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
-------------------------------------------------------------------------------- */
static void SetSysClock(void)
{
SystemCoreClock = 48000000;
/* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
/* At this stage the HSI is already enabled */
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
/* PLL configuration = (HSI/2) * 12 = ~48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_DIV2 | RCC_CFGR_PLLMUL12);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}
/*--------------------------------------------------------------------------------*/
// Button_Init(void) ;Initialize button
// PC.13 to control User botton, set PC.13 is input pin
/*--------------------------------------------------------------------------------*/
void Button_Init(void) {
RCC->AHBENR |= (1ul << 19); // Enable GPIOC clock
GPIOC->MODER &= ~(3ul << 2*13); // Set PC.13 is input
}
/*------------------------------------------------------------------------------*/
//uint32_t Button_GetState(void)
// Get USER button (PC.13) state
// return: 1 means USER key pressed
/*------------------------------------------------------------------------------*/
uint32_t Button_GetState (void) {
uint32_t val = 0;
if ((GPIOC->IDR & (1ul << 13)) == 0) { //When USER button pressed PC.13=0
val |= USER; // set USER button pressed
}
return (val);
}
/*--------------------------------------------------------------------------------*/
// MPU setup process
/*--------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------*/
// The processor clock is initialized by CMSIS startup + system file
/*--------------------------------------------------------------------------------*/
int main (void) { // User application starts here
/* Configure the System clock frequency, AHB/APBx prescalers and Flash settings */
SetSysClock();
stdout_init(); // Initialize USART 2(PA3 to USART2_RX,PA2 to USART2_TX)
SysTick_Config(SystemCoreClock/1000); // System Tick Initializes,set SysTick 1ms interrupt
GPIO_Configuration();
LCD1602_Init();
Config_PA910(); // for Bluetooth PA.9(Tx)->HC05(Rx), PA.10(Rx)->HC05(Tx)
Config_uart1(); // for BlueTooth
//------------------------------------------
unsigned char str[]="Hello world!";
unsigned char *w=str;
u8 word;
u8 x, y, i;
x= 0 ;
//while(1) {
LCD1602_ClearScreen();
//----------print Hello------------------------------
LCD1602_SetCursor( 0, 0 );
LCD1602_Show_Str( 2, 0, w );
Delay(1000);
LCD1602_ClearScreen();
//------------print A--------------------------
//-----------auto chang line-------------------------------
word=0x41ul;
for(i=0; i<32;i++){
y = i/16;
x = i-16;
if (y==0){ LCD1602_SetCursor( i, y);}
if (y==1){ LCD1602_SetCursor( x, y);}
LCD1602_WriteData(word+i);
Delay(50);
}
//-----------Read Address-------------------------------
u8 Hex[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
u8 line1[] ={'a','d','d','r',':',0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul} ;
u8 line2[] ={0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul,0x20ul} ;
u8 *lineu=line1;
u8 *lined=line2;
u8 addr= LCD_ReadADDR();
line1[7] = Hex[(addr >> 4) & 0xful];
line1[8] = Hex[(addr) & 0xful];
//--------show line1 line2 --------------------------------------
LCD1602_show( lineu, lined);
//-----------------------------------------------------
LCD1602_SetCursor( 0, 1 );
// int h=0;
for (i=5; i<25 ;i++) {
//PutCha(i);
LCD1602_WriteData(word+i);
if (USART1->ISR &( 0x1ul <<7)) {
USART1->TDR =word+i;
Delay(100);
}
}
//-----------------------------------------------------
LCD1602_SetCursor( 0, 1 );
u8 pos =0;
u8 buffer=0;
uint8_t data[20];
USART1->CR1 = USART_CR1_RXNEIE | USART_CR1_RE | USART_CR1_UE;
while(1){
for (buffer=0;buffer<20; buffer++)
{
while ((USART1->ISR & USART_ISR_RXNE) == USART_ISR_RXNE)
{
data[buffer] = (uint8_t) USART1->RDR; //receive data
}
}
/* for(i=0; i<=buffer;i++){ LCD1602_WriteData(data[i]); pos++;}
buffer++;
if ((data ==0x0d) || (data ==0x0a)) {;}
else {
LCD1602_WriteData(Hex[(data >> 4) & 0xful]);
LCD1602_WriteData( Hex[(data) & 0xful]);
pos +=2;*/
if (pos>16){
pos=0;
LCD1602_SetCursor( 0, 1 );}
}
//------------------------------------------------
}
|